Repository: eslint/eslint
Pull request #8280 (2017-03-18 02:32:49)

Chore: Switch to eslint-scope from escope
**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain:
Switches to eslint-scope for 4.0.0 per #8266

<!--
    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)**
Remove escope and replaced with eslint-scope

**Is there anything you'd like reviewers to focus on?**
Nope is a drop in replacement no changes to eslint


eslintbot: LGTM
mention-bot: @corbinu, thanks for your PR! By analyzing the history of the files in this pull request, we identified @mysticatea, @vitorbal and @kaicataldo to be potential reviewers.
corbinu: @not-an-aardvark It looks like the failures are only in phantomjs. Is it possible that our upgrading escope to run only on Node 4 included some JS that Phantom can't handle?
not-an-aardvark: You're right, it seems to be an issue with our build. I think it's because we're running babelify [here](https://github.com/eslint/eslint/blob/602e9c2a08c08f5827b34e075846b35770c15706/Makefile.js#L770) to get ESLint to work with PhantomJS, but it's not getting run on dependencies for some reason.
not-an-aardvark: Changing the `-t` in [this line](https://github.com/eslint/eslint/blob/602e9c2a08c08f5827b34e075846b35770c15706/Makefile.js#L770) to `--global-transform` seems to fix the build. I'm not sure if there's a better way to do this.
corbinu: Well I can make that change if that's what you think is best. I might also propose maybe we should switch out phantomjs for electron: https://github.com/twolfson/karma-electron/blob/master/README.md
not-an-aardvark: I'm not really familiar with the advantages/disadvantages of the tooling options here. For this PR, I think it would probably be better to keep phantomjs. Then we can switch to electron in another PR if necessary. (I want to keep the commits as atomic as possible.)
alberto: @corbinu We are using phantomjs to ensure eslint runs fine in a browser environment. I don't think `karma-electron` gives us that.
mysticatea: `electron` does not a headless browser, so it requires virtual display to run in Travis CI. I'm not sure the choice is proper.
I'd like vote to the use of global transform of `browserify`. (this implies we have to use the global transform for our online demo to support IE11)
soda0289: PhantomJS 2.5 beta supports es6 features like `const` if you want to give that a shot.
https://github.com/ariya/phantomjs/issues/14506
https://bitbucket.org/ariya/phantomjs/downloads/
not-an-aardvark: The issue isn't really that PhantomJS doesn't support ES6, it's that our bundle contains ES6. So things like the demo wouldn't work correctly on old browsers.
soda0289: Could we transform eslint-scope during publish? I think it used to use babel to do this but it was removed since we were only targeting node v4
not-an-aardvark: Yes, I think that's effectively what `--global-transform` does with browserify.
corbinu: @not-an-aardvark No was not proposing switching to electron in this commit just as a general solution. 

I guess I did not know eslint supported browsers at all. What browser versions do we need to support?
not-an-aardvark: I don't think we officially support anything in browsers, it's just that we need the [demo](http://eslint.org/demo) to work in ES5 browsers.
corbinu: Ahh ok so basically IE11 is the only issue (I feel like we all are going to spend the next 3 years saying that). Ya global transform is what you want then will push and we should be good
eslintbot: LGTM
eslintbot: LGTM
ilyavolodin: If IE11 is giving us trouble, we could consider dropping support for it for demo (just need to add code for non-supported browsers). In the last 3 month, IE was only 1.08% of browsers visiting the site. And while that's still a pretty large number (around 5.8k sessions), demo has a lot less people visiting it. For demo page only IE is 1.1% of visits, but it's also only 105 pageviews in the last 3 month. So I think that could allow us to drop support for ES5 browsers (and remove babel from our test scripts).
not-an-aardvark: I agree that we shouldn't do additional work to support ES5 browsers. But in this case, if we can change a line of our build script to continue to support them without much extra development effort, it seems worthwhile.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 856d960eb..4f4b3bbdb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,42 @@
+v3.19.0 - March 31, 2017
+
+* e09132f Fix: no-extra-parens false positive with exports and object literals (#8359) (Teddy Katz)
+* 91baed4 Update: allow custom messages in no-restricted-syntax (fixes #8298) (#8357) (Vitor Balocco)
+* 35c93e6 Fix: prevent space-before-function-paren from checking type annotations (#8349) (Teddy Katz)
+* 3342e9f Fix: don't modify operator precedence in operator-assignment autofixer (#8358) (Teddy Katz)
+* f88375f Docs: clarify that no-unsafe-negation is in eslint:recommended (#8371) (Teddy Katz)
+* 02f0d27 Docs: Add soda0289 to Development Team (#8367) (Kai Cataldo)
+* 155424c Fix: ignore empty path in patterns (fixes #8362) (#8364) (alberto)
+* 27616a8 Fix: prefer-const false positive with object spread (fixes #8187) (#8297) (Vitor Balocco)
+* 8569a90 Docs: add note about git's linebreak handling to linebreak-style docs (#8361) (Teddy Katz)
+* 5878593 Chore: fix invalid syntax in no-param-reassign test (#8360) (Teddy Katz)
+* 1b1046b Fix: don't classify plugins that throw errors as "missing" (fixes #6874) (#8323) (Teddy Katz)
+* 29f4ba5 Fix: no-useless-computed-key invalid autofix for getters and setters (#8335) (Teddy Katz)
+* 0541eaf Fix: no-implicit-coercion invalid autofix with consecutive identifiers (#8340) (Teddy Katz)
+* 41b9786 Fix: no-extra-parens false positive with objects following arrows (#8339) (Teddy Katz)
+* 3146167 Fix: `eslint.verify` should not mutate config argument (fixes #8329) (#8334) (alberto)
+* 927de90 Fix: dot-notation autofix produces invalid syntax for integer properties (#8332) (Teddy Katz)
+* a9d1bea Fix: comma-style autofix produces errors on parenthesized elements (#8331) (Teddy Katz)
+* d52173f Fix: don't generate invalid options in config-rule (#8326) (Teddy Katz)
+* 6eda3b5 Fix: no-extra-parens invalid autofix in for-of statements (#8337) (Teddy Katz)
+* 6c819d8 Fix: dot-notation autofix produces errors on parenthesized computed keys (#8330) (Teddy Katz)
+* 2d883d7 Fix: object-shorthand autofix produces errors on parenthesized functions (#8328) (Teddy Katz)
+* cd9b774 Fix: quotes false positive with backtick option in method names (#8327) (Teddy Katz)
+* d064ba2 Fix: no-else-return false positive for ifs in single-statement position (#8338) (Teddy Katz)
+* 6a718ba Chore: enable max-statements-per-line on ESLint codebase (#8321) (Teddy Katz)
+* 614b62e Chore: update sinon calls to deprecated API. (#8310) (alberto)
+* 0491572 Chore: use precalculated counts in codeframe formatter (#8296) (Vitor Balocco)
+* 8733e6a Chore: Fix incorrect error location properties in tests (#8307) (alberto)
+* c4ffb49 Chore: Fix typos in test option assertions (#8305) (Teddy Katz)
+* 79a97cb Upgrade: devDependencies (#8303) (alberto)
+* e4da200 Upgrade: Mocha to 3.2.0 (#8299) (Ilya Volodin)
+* 2f144ca Fix: operator-assignment autofix errors with parentheses (fixes #8293) (#8294) (Teddy Katz)
+* 7521cd5 Chore: update token logic in rules to use ast-utils (#8288) (Teddy Katz)
+* 9b509ce Chore: refactor space-before-function-paren rule (#8284) (Teddy Katz)
+* ddc6350 Fix: no-param-reassign false positive on destructuring (fixes #8279) (#8281) (Teddy Katz)
+* f8176b3 Chore: improve test coverage for node-event-generator (#8287) (Teddy Katz)
+* 602e9c2 Docs: fix incorrect selector examples (#8278) (Teddy Katz)
+
 v3.18.0 - March 17, 2017
 
 * 85f74ca Fix: broken code path of direct nested loops (fixes #8248) (#8274) (Toru Nagashima)
diff --git a/Makefile.js b/Makefile.js
index 60f02b58c..0917a96b3 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -767,7 +767,7 @@ target.browserify = function() {
     generateRulesIndex(TEMP_DIR);
 
     // 5. browserify the temp directory
-    nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}eslint.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "-t [ babelify --presets [ es2015 ] ]");
+    nodeCLI.exec("browserify", "-x espree", `${TEMP_DIR}eslint.js`, "-o", `${BUILD_DIR}eslint.js`, "-s eslint", "--global-transform [ babelify --presets [ es2015 ] ]");
 
     // 6. Browserify espree
     nodeCLI.exec("browserify", "-r espree", "-o", `${TEMP_DIR}espree.js`);
diff --git a/README.md b/README.md
index a08f276fc..1ccdbb9bf 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,7 @@ These folks keep the project moving and are resources for help.
 * Kevin Partington ([@platinumazure](https://github.com/platinumazure))
 * Vitor Balocco ([@vitorbal](https://github.com/vitorbal))
 * James Henry ([@JamesHenry](https://github.com/JamesHenry))
+* Reyad Attiyat ([@soda0289](https://github.com/soda0289))
 
 ## Releases
 
diff --git a/docs/rules/linebreak-style.md b/docs/rules/linebreak-style.md
index 9b7580e00..96f6c9f50 100644
--- a/docs/rules/linebreak-style.md
+++ b/docs/rules/linebreak-style.md
@@ -67,9 +67,19 @@ function foo(params) { // \r\n
 } // \r\n
 ```
 
+## Using this rule with version control systems
+
+Version control systems sometimes have special behavior for linebreaks. To make it easy for developers to contribute to your codebase from different platforms, you may want to configure your VCS to handle linebreaks appropriately.
+
+For example, the default behavior of [git](https://git-scm.com/) on Windows systems is to convert LF linebreaks to CRLF when checking out files, but to store the linebreaks as LF when committing a change. This will cause the `linebreak-style` rule to report errors if configured with the `"unix"` setting, because the files that ESLint sees will have CRLF linebreaks. If you use git, you may want to add a line to your [`.gitattributes` file](https://git-scm.com/docs/gitattributes) to prevent git from converting linebreaks in `.js` files:
+
+```
+*.js text eol=lf
+```
+
 ## When Not To Use It
 
-If you aren't concerned about having different line endings within you code, then you can safely turn this rule off.
+If you aren't concerned about having different line endings within your code, then you can safely turn this rule off.
 
 ## Compatibility
 
diff --git a/docs/rules/no-restricted-syntax.md b/docs/rules/no-restricted-syntax.md
index ffe763c8b..8efbd780e 100644
--- a/docs/rules/no-restricted-syntax.md
+++ b/docs/rules/no-restricted-syntax.md
@@ -12,7 +12,7 @@ This rule disallows specified (that is, user-defined) syntax.
 
 ## Options
 
-This rule takes a list of strings:
+This rule takes a list of strings, where each string is an AST selector:
 
 ```json
 {
@@ -22,6 +22,30 @@ This rule takes a list of strings:
 }
 ```
 
+Alternatively, the rule also accepts objects, where the selector and an optional custom message are specified:
+
+```json
+{
+    "rules": {
+        "no-restricted-syntax": [
+            "error",
+            {
+                "selector": "FunctionExpression",
+                "message": "Function expressions are not allowed."
+            },
+            {
+                "selector": "CallExpression[callee.name='setTimeout'][arguments.length!=2]",
+                "message": "setTimeout must always be invoked with two arguments."
+            }
+        ]
+    }
+}
+```
+
+If a custom message is specified with the `message` property, ESLint will use that message when reporting occurrences of the syntax specified in the `selector` property.
+
+The string and object formats can be freely mixed in the configuration as needed.
+
 Examples of **incorrect** code for this rule with the `"FunctionExpression", "WithStatement", BinaryExpression[operator='in']` options:
 
 ```js
diff --git a/lib/ast-utils.js b/lib/ast-utils.js
index 0f2f3d6af..978f19ad2 100644
--- a/lib/ast-utils.js
+++ b/lib/ast-utils.js
@@ -556,9 +556,9 @@ module.exports = {
     /**
      * Finds the variable by a given name in a given scope and its upper scopes.
      *
-     * @param {escope.Scope} initScope - A scope to start find.
+     * @param {eslint-scope.Scope} initScope - A scope to start find.
      * @param {string} name - A variable name to find.
-     * @returns {escope.Variable|null} A found variable or `null`.
+     * @returns {eslint-scope.Variable|null} A found variable or `null`.
      */
     getVariableByName(initScope, name) {
         let scope = initScope;
diff --git a/lib/config/config-rule.js b/lib/config/config-rule.js
index bd7aa13b9..a8a073caa 100644
--- a/lib/config/config-rule.js
+++ b/lib/config/config-rule.js
@@ -223,7 +223,7 @@ class RuleConfigSet {
     /**
     * Add rule configurations from a schema object
     * @param  {Object} obj Schema item with type === "object"
-    * @returns {void}
+    * @returns {boolean} true if at least one schema for the object could be generated, false otherwise
     */
     addObject(obj) {
         const objectConfigSet = {
@@ -258,7 +258,10 @@ class RuleConfigSet {
 
         if (objectConfigSet.objectConfigs.length > 0) {
             this.ruleConfigs = this.ruleConfigs.concat(combineArrays(this.ruleConfigs, objectConfigSet.objectConfigs));
+            return true;
         }
+
+        return false;
     }
 }
 
@@ -271,20 +274,21 @@ function generateConfigsFromSchema(schema) {
     const configSet = new RuleConfigSet();
 
     if (Array.isArray(schema)) {
-        schema.forEach(opt => {
+        for (const opt of schema) {
             if (opt.enum) {
                 configSet.addEnums(opt.enum);
-            }
-
-            if (opt.type && opt.type === "object") {
-                configSet.addObject(opt);
-            }
+            } else if (opt.type && opt.type === "object") {
+                if (!configSet.addObject(opt)) {
+                    break;
+                }
 
-            if (opt.oneOf) {
+            // TODO (IanVS): support oneOf
+            } else {
 
-                // TODO (IanVS): not yet implemented
+                // If we don't know how to fill in this option, don't fill in any of the following options.
+                break;
             }
-        });
+        }
     }
     configSet.addErrorSeverity();
     return configSet.ruleConfigs;
diff --git a/lib/config/plugins.js b/lib/config/plugins.js
index 5073d564a..e28a77929 100644
--- a/lib/config/plugins.js
+++ b/lib/config/plugins.js
@@ -127,14 +127,25 @@ module.exports = {
         if (!plugins[shortName]) {
             try {
                 plugin = require(longName);
-            } catch (err) {
-                debug(`Failed to load plugin ${longName}.`);
-                err.message = `Failed to load plugin ${pluginName}: ${err.message}`;
-                err.messageTemplate = "plugin-missing";
-                err.messageData = {
-                    pluginName: longName
-                };
-                throw err;
+            } catch (pluginLoadErr) {
+                try {
+
+                    // Check whether the plugin exists
+                    require.resolve(longName);
+                } catch (missingPluginErr) {
+
+                    // If the plugin can't be resolved, display the missing plugin error (usually a config or install error)
+                    debug(`Failed to load plugin ${longName}.`);
+                    missingPluginErr.message = `Failed to load plugin ${pluginName}: ${missingPluginErr.message}`;
+                    missingPluginErr.messageTemplate = "plugin-missing";
+                    missingPluginErr.messageData = {
+                        pluginName: longName
+                    };
+                    throw missingPluginErr;
+                }
+
+                // Otherwise, the plugin exists and is throwing on module load for some reason, so print the stack trace.
+                throw pluginLoadErr;
             }
 
             this.define(pluginName, plugin);
diff --git a/lib/eslint.js b/lib/eslint.js
index 3c23a7495..1d8468235 100755
--- a/lib/eslint.js
+++ b/lib/eslint.js
@@ -11,7 +11,7 @@
 
 const assert = require("assert"),
     EventEmitter = require("events").EventEmitter,
-    escope = require("escope"),
+    eslintScope = require("eslint-scope"),
     levn = require("levn"),
     blankScriptAST = require("../conf/blank-script.json"),
     DEFAULT_PARSER = require("../conf/eslint-recommended").parser,
@@ -187,7 +187,7 @@ function addDeclaredGlobals(program, globalScope, config) {
         let variable = globalScope.set.get(name);
 
         if (!variable) {
-            variable = new escope.Variable(name, globalScope);
+            variable = new eslintScope.Variable(name, globalScope);
             variable.eslintExplicitGlobal = false;
             globalScope.variables.push(variable);
             globalScope.set.set(name, variable);
@@ -199,7 +199,7 @@ function addDeclaredGlobals(program, globalScope, config) {
         let variable = globalScope.set.get(name);
 
         if (!variable) {
-            variable = new escope.Variable(name, globalScope);
+            variable = new eslintScope.Variable(name, globalScope);
             variable.eslintExplicitGlobal = true;
             variable.eslintExplicitGlobalComment = explicitGlobals[name].comment;
             globalScope.variables.push(variable);
@@ -778,17 +778,18 @@ module.exports = (function() {
         // search and apply "eslint-env *".
         const envInFile = findEslintEnv(text || textOrSourceCode.text);
 
+        config = Object.assign({}, config);
+
         if (envInFile) {
-            if (!config || !config.env) {
-                config = Object.assign({}, config || {}, { env: envInFile });
-            } else {
-                config = Object.assign({}, config);
+            if (config.env) {
                 config.env = Object.assign({}, config.env, envInFile);
+            } else {
+                config.env = envInFile;
             }
         }
 
         // process initial config to make it safe to extend
-        config = prepareConfig(config || {});
+        config = prepareConfig(config);
 
         // only do this for text
         if (text !== null) {
@@ -888,7 +889,7 @@ module.exports = (function() {
             const ecmaVersion = currentConfig.parserOptions.ecmaVersion || 5;
 
             // gather scope data that may be needed by the rules
-            scopeManager = escope.analyze(ast, {
+            scopeManager = eslintScope.analyze(ast, {
                 ignoreEval: true,
                 nodejsScope: ecmaFeatures.globalReturn,
                 impliedStrict: ecmaFeatures.impliedStrict,
@@ -1222,7 +1223,7 @@ module.exports = (function() {
      * - others - always an empty array.
      *
      * @param {ASTNode} node A node to get.
-     * @returns {escope.Variable[]} Variables that are declared by the node.
+     * @returns {eslint-scope.Variable[]} Variables that are declared by the node.
      */
     api.getDeclaredVariables = function(node) {
         return (scopeManager && scopeManager.getDeclaredVariables(node)) || [];
diff --git a/lib/formatters/codeframe.js b/lib/formatters/codeframe.js
index 39ba06de4..1191ccb8e 100644
--- a/lib/formatters/codeframe.js
+++ b/lib/formatters/codeframe.js
@@ -101,15 +101,10 @@ module.exports = function(results) {
     const resultsWithMessages = results.filter(result => result.messages.length > 0);
 
     let output = resultsWithMessages.reduce((resultsOutput, result) => {
-        const messages = result.messages.map(message => {
-            if (message.fatal || message.severity === 2) {
-                errors++;
-            } else {
-                warnings++;
-            }
-
-            return `${formatMessage(message, result)}\n\n`;
-        });
+        const messages = result.messages.map(message => `${formatMessage(message, result)}\n\n`);
+
+        errors += result.errorCount;
+        warnings += result.warningCount;
 
         return resultsOutput.concat(messages);
     }, []).join("\n");
diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js
index 74329ca0f..f2f14245b 100644
--- a/lib/rules/arrow-body-style.js
+++ b/lib/rules/arrow-body-style.js
@@ -100,7 +100,7 @@ module.exports = {
                             const firstValueToken = sourceCode.getTokenAfter(returnKeyword);
                             let lastValueToken = sourceCode.getLastToken(blockBody[0]);
 
-                            if (lastValueToken.type === "Punctuator" && lastValueToken.value === ";") {
+                            if (astUtils.isSemicolonToken(lastValueToken)) {
 
                                 /* The last token of the returned value is the last token of the ReturnExpression (if
                                  * the ReturnExpression has no semicolon), or the second-to-last token (if the ReturnExpression
@@ -120,7 +120,7 @@ module.exports = {
                             const textBeforeReturn = sourceText.slice(arrowBody.range[0] + 1, returnKeyword.range[0]);
                             const textBetweenReturnAndValue = sourceText.slice(returnKeyword.range[1], firstValueToken.range[0]);
                             const rawReturnValueText = sourceText.slice(firstValueToken.range[0], lastValueToken.range[1]);
-                            const returnValueText = firstValueToken.value === "{" ? `(${rawReturnValueText})` : rawReturnValueText;
+                            const returnValueText = astUtils.isOpeningBraceToken(firstValueToken) ? `(${rawReturnValueText})` : rawReturnValueText;
                             const textAfterValue = sourceText.slice(lastValueToken.range[1], blockBody[0].range[1] - 1);
                             const textAfterReturnStatement = sourceText.slice(blockBody[0].range[1], arrowBody.range[1] - 1);
 
diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js
index e069e307e..c292d1b49 100644
--- a/lib/rules/arrow-parens.js
+++ b/lib/rules/arrow-parens.js
@@ -4,6 +4,12 @@
  */
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("../ast-utils");
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -62,7 +68,7 @@ module.exports = {
                 node.body.type !== "BlockStatement" &&
                 !node.returnType
             ) {
-                if (token.type === "Punctuator" && token.value === "(") {
+                if (astUtils.isOpeningParenToken(token)) {
                     context.report({
                         node,
                         message: requireForBlockBodyMessage,
@@ -84,7 +90,7 @@ module.exports = {
                 requireForBlockBody &&
                 node.body.type === "BlockStatement"
             ) {
-                if (token.type !== "Punctuator" || token.value !== "(") {
+                if (!astUtils.isOpeningParenToken(token)) {
                     context.report({
                         node,
                         message: requireForBlockBodyNoParensMessage,
@@ -103,7 +109,7 @@ module.exports = {
                 !node.params[0].typeAnnotation &&
                 !node.returnType
             ) {
-                if (token.type === "Punctuator" && token.value === "(") {
+                if (astUtils.isOpeningParenToken(token)) {
                     context.report({
                         node,
                         message: asNeededMessage,
diff --git a/lib/rules/block-scoped-var.js b/lib/rules/block-scoped-var.js
index bb0931a3c..0b4d855fa 100644
--- a/lib/rules/block-scoped-var.js
+++ b/lib/rules/block-scoped-var.js
@@ -41,7 +41,7 @@ module.exports = {
 
         /**
          * Reports a given reference.
-         * @param {escope.Reference} reference - A reference to report.
+         * @param {eslint-scope.Reference} reference - A reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/comma-dangle.js b/lib/rules/comma-dangle.js
index bf9d7c48c..17066d947 100644
--- a/lib/rules/comma-dangle.js
+++ b/lib/rules/comma-dangle.js
@@ -10,6 +10,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash");
+const astUtils = require("../ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -178,7 +179,7 @@ module.exports = {
                 default: {
                     const nextToken = sourceCode.getTokenAfter(lastItem);
 
-                    if (nextToken.value === ",") {
+                    if (astUtils.isCommaToken(nextToken)) {
                         return nextToken;
                     }
                     return sourceCode.getLastToken(lastItem);
@@ -224,7 +225,7 @@ module.exports = {
 
             const trailingToken = getTrailingToken(node, lastItem);
 
-            if (trailingToken.value === ",") {
+            if (astUtils.isCommaToken(trailingToken)) {
                 context.report({
                     node: lastItem,
                     loc: trailingToken.loc.start,
diff --git a/lib/rules/comma-spacing.js b/lib/rules/comma-spacing.js
index 6acd774a0..bb1dd68f6 100644
--- a/lib/rules/comma-spacing.js
+++ b/lib/rules/comma-spacing.js
@@ -53,16 +53,6 @@ module.exports = {
         // list of comma tokens to ignore for the check of leading whitespace
         const commaTokensToIgnore = [];
 
-        /**
-         * Determines if a given token is a comma operator.
-         * @param {ASTNode} token The token to check.
-         * @returns {boolean} True if the token is a comma, false if not.
-         * @private
-         */
-        function isComma(token) {
-            return !!token && (token.type === "Punctuator") && (token.value === ",");
-        }
-
         /**
          * Reports a spacing error with an appropriate message.
          * @param {ASTNode} node The binary expression node to report.
@@ -147,7 +137,7 @@ module.exports = {
                 if (element === null) {
                     token = sourceCode.getTokenAfter(previousToken);
 
-                    if (isComma(token)) {
+                    if (astUtils.isCommaToken(token)) {
                         commaTokensToIgnore.push(token);
                     }
                 } else {
@@ -166,7 +156,7 @@ module.exports = {
             "Program:exit"() {
                 tokensAndComments.forEach((token, i) => {
 
-                    if (!isComma(token)) {
+                    if (!astUtils.isCommaToken(token)) {
                         return;
                     }
 
@@ -179,8 +169,8 @@ module.exports = {
 
                     validateCommaItemSpacing({
                         comma: token,
-                        left: isComma(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken,
-                        right: isComma(nextToken) ? null : nextToken
+                        left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.indexOf(token) > -1 ? null : previousToken,
+                        right: astUtils.isCommaToken(nextToken) ? null : nextToken
                     }, token);
                 });
             },
diff --git a/lib/rules/comma-style.js b/lib/rules/comma-style.js
index 74fee9623..fcaecc662 100644
--- a/lib/rules/comma-style.js
+++ b/lib/rules/comma-style.js
@@ -63,16 +63,6 @@ module.exports = {
         // Helpers
         //--------------------------------------------------------------------------
 
-        /**
-         * Determines if a given token is a comma operator.
-         * @param {ASTNode} token The token to check.
-         * @returns {boolean} True if the token is a comma, false if not.
-         * @private
-         */
-        function isComma(token) {
-            return !!token && (token.type === "Punctuator") && (token.value === ",");
-        }
-
         /**
          * Modified text based on the style
          * @param {string} styleType Style type
@@ -192,7 +182,7 @@ module.exports = {
                         tokenBeforeComma = sourceCode.getTokenBefore(commaToken);
 
                     // Check if previous token is wrapped in parentheses
-                    if (tokenBeforeComma && tokenBeforeComma.value === ")") {
+                    if (tokenBeforeComma && astUtils.isClosingParenToken(tokenBeforeComma)) {
                         previousItemToken = tokenBeforeComma;
                     }
 
@@ -210,12 +200,16 @@ module.exports = {
                      * All comparisons are done based on these tokens directly, so
                      * they are always valid regardless of an undefined item.
                      */
-                    if (isComma(commaToken)) {
+                    if (astUtils.isCommaToken(commaToken)) {
                         validateCommaItemSpacing(previousItemToken, commaToken,
                                 currentItemToken, reportItem);
                     }
 
-                    previousItemToken = item ? sourceCode.getLastToken(item) : previousItemToken;
+                    if (item) {
+                        const tokenAfterItem = sourceCode.getTokenAfter(item, astUtils.isNotClosingParenToken);
+
+                        previousItemToken = tokenAfterItem ? sourceCode.getTokenBefore(tokenAfterItem) : sourceCode.ast.tokens[sourceCode.ast.tokens.length - 1];
+                    }
                 });
 
                 /*
@@ -229,7 +223,7 @@ module.exports = {
                     const lastToken = sourceCode.getLastToken(node),
                         nextToLastToken = sourceCode.getTokenBefore(lastToken);
 
-                    if (isComma(nextToLastToken)) {
+                    if (astUtils.isCommaToken(nextToLastToken)) {
                         validateCommaItemSpacing(
                             sourceCode.getTokenBefore(nextToLastToken),
                             nextToLastToken,
diff --git a/lib/rules/curly.js b/lib/rules/curly.js
index 896abf04a..cd15b2d93 100644
--- a/lib/rules/curly.js
+++ b/lib/rules/curly.js
@@ -76,7 +76,7 @@ module.exports = {
         function isCollapsedOneLiner(node) {
             const before = sourceCode.getTokenBefore(node);
             const last = sourceCode.getLastToken(node);
-            const lastExcludingSemicolon = last.type === "Punctuator" && last.value === ";" ? sourceCode.getTokenBefore(last) : last;
+            const lastExcludingSemicolon = astUtils.isSemicolonToken(last) ? sourceCode.getTokenBefore(last) : last;
 
             return before.loc.start.line === lastExcludingSemicolon.loc.end.line;
         }
@@ -174,7 +174,7 @@ module.exports = {
             const tokenAfter = sourceCode.getTokenAfter(closingBracket);
             const lastBlockNode = sourceCode.getNodeByRangeIndex(tokenBefore.range[0]);
 
-            if (tokenBefore.value === ";") {
+            if (astUtils.isSemicolonToken(tokenBefore)) {
 
                 // If the last statement already has a semicolon, don't add another one.
                 return false;
diff --git a/lib/rules/dot-notation.js b/lib/rules/dot-notation.js
index d55b098b2..abb9b4b48 100644
--- a/lib/rules/dot-notation.js
+++ b/lib/rules/dot-notation.js
@@ -4,6 +4,12 @@
  */
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("../ast-utils");
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -64,20 +70,20 @@ module.exports = {
                                 propertyValue: JSON.stringify(node.property.value)
                             },
                             fix(fixer) {
-                                const leftBracket = sourceCode.getTokenBefore(node.property);
-                                const rightBracket = sourceCode.getTokenAfter(node.property);
-                                const textBeforeProperty = sourceCode.text.slice(leftBracket.range[1], node.property.range[0]);
-                                const textAfterProperty = sourceCode.text.slice(node.property.range[1], rightBracket.range[0]);
+                                const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
+                                const rightBracket = sourceCode.getLastToken(node);
 
-                                if (textBeforeProperty.trim() || textAfterProperty.trim()) {
+                                if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {
 
                                     // Don't perform any fixes if there are comments inside the brackets.
                                     return null;
                                 }
 
+                                const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
+
                                 return fixer.replaceTextRange(
                                     [leftBracket.range[0], rightBracket.range[1]],
-                                    `.${node.property.value}`
+                                    `${textBeforeDot}.${node.property.value}`
                                 );
                             }
                         });
diff --git a/lib/rules/func-names.js b/lib/rules/func-names.js
index e7f950c9b..848ce9757 100644
--- a/lib/rules/func-names.js
+++ b/lib/rules/func-names.js
@@ -13,7 +13,7 @@ const astUtils = require("../ast-utils");
 
 /**
  * Checks whether or not a given variable is a function name.
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function name.
  */
 function isFunctionName(variable) {
diff --git a/lib/rules/global-require.js b/lib/rules/global-require.js
index 367fe590e..beda8d99f 100644
--- a/lib/rules/global-require.js
+++ b/lib/rules/global-require.js
@@ -17,7 +17,7 @@ const ACCEPTABLE_PARENTS = [
 ];
 
 /**
- * Finds the escope reference in the given scope.
+ * Finds the eslint-scope reference in the given scope.
  * @param {Object} scope The scope to search.
  * @param {ASTNode} node The identifier node.
  * @returns {Reference|null} Returns the found reference or null if none were found.
diff --git a/lib/rules/lines-around-directive.js b/lib/rules/lines-around-directive.js
index 7a4b21ea1..89dd9c6ae 100644
--- a/lib/rules/lines-around-directive.js
+++ b/lib/rules/lines-around-directive.js
@@ -74,7 +74,7 @@ module.exports = {
             const lastToken = sourceCode.getLastToken(node);
             const secondToLastToken = sourceCode.getTokenBefore(lastToken);
 
-            return lastToken.type === "Punctuator" && lastToken.value === ";" && lastToken.loc.start.line > secondToLastToken.loc.end.line
+            return astUtils.isSemicolonToken(lastToken) && lastToken.loc.start.line > secondToLastToken.loc.end.line
                 ? secondToLastToken
                 : lastToken;
         }
diff --git a/lib/rules/new-parens.js b/lib/rules/new-parens.js
index b0fc5ba97..ad37979d5 100644
--- a/lib/rules/new-parens.js
+++ b/lib/rules/new-parens.js
@@ -6,28 +6,14 @@
 "use strict";
 
 //------------------------------------------------------------------------------
-// Helpers
+// Requirements
 //------------------------------------------------------------------------------
 
-/**
- * Checks whether the given token is an opening parenthesis or not.
- *
- * @param {Token} token - The token to check.
- * @returns {boolean} `true` if the token is an opening parenthesis.
- */
-function isOpeningParen(token) {
-    return token.type === "Punctuator" && token.value === "(";
-}
+const astUtils = require("../ast-utils");
 
-/**
- * Checks whether the given token is an closing parenthesis or not.
- *
- * @param {Token} token - The token to check.
- * @returns {boolean} `true` if the token is an closing parenthesis.
- */
-function isClosingParen(token) {
-    return token.type === "Punctuator" && token.value === ")";
-}
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -56,8 +42,8 @@ module.exports = {
                 }
 
                 const lastToken = sourceCode.getLastToken(node);
-                const hasLastParen = lastToken && isClosingParen(lastToken);
-                const hasParens = hasLastParen && isOpeningParen(sourceCode.getTokenBefore(lastToken));
+                const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
+                const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));
 
                 if (!hasParens) {
                     context.report({
diff --git a/lib/rules/no-alert.js b/lib/rules/no-alert.js
index f2cfc3a87..232fa1444 100644
--- a/lib/rules/no-alert.js
+++ b/lib/rules/no-alert.js
@@ -35,7 +35,7 @@ function report(context, node, identifierName) {
 }
 
 /**
- * Finds the escope reference in the given scope.
+ * Finds the eslint-scope reference in the given scope.
  * @param {Object} scope The scope to search.
  * @param {ASTNode} node The identifier node.
  * @returns {Reference|null} Returns the found reference or null if none were found.
diff --git a/lib/rules/no-cond-assign.js b/lib/rules/no-cond-assign.js
index 4c4e8f5ad..61e5751e4 100644
--- a/lib/rules/no-cond-assign.js
+++ b/lib/rules/no-cond-assign.js
@@ -66,19 +66,6 @@ module.exports = {
             return null;
         }
 
-        /**
-         * Check whether the code represented by an AST node is enclosed in parentheses.
-         * @param {!Object} node The node to test.
-         * @returns {boolean} `true` if the code is enclosed in parentheses; otherwise, `false`.
-         */
-        function isParenthesised(node) {
-            const previousToken = sourceCode.getTokenBefore(node),
-                nextToken = sourceCode.getTokenAfter(node);
-
-            return previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
-                nextToken.value === ")" && nextToken.range[0] >= node.range[1];
-        }
-
         /**
          * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
          * @param {!Object} node The node to test.
@@ -88,9 +75,9 @@ module.exports = {
             const previousToken = sourceCode.getTokenBefore(node, 1),
                 nextToken = sourceCode.getTokenAfter(node, 1);
 
-            return isParenthesised(node) &&
-                previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
-                nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+            return astUtils.isParenthesised(sourceCode, node) &&
+                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
+                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
         }
 
         /**
@@ -102,7 +89,7 @@ module.exports = {
             if (node.test &&
                 (node.test.type === "AssignmentExpression") &&
                 (node.type === "ForStatement"
-                    ? !isParenthesised(node.test)
+                    ? !astUtils.isParenthesised(sourceCode, node.test)
                     : !isParenthesisedTwice(node.test)
                 )
             ) {
diff --git a/lib/rules/no-console.js b/lib/rules/no-console.js
index 9131a49a0..32bdf6d1f 100644
--- a/lib/rules/no-console.js
+++ b/lib/rules/no-console.js
@@ -48,7 +48,7 @@ module.exports = {
         /**
          * Checks whether the given reference is 'console' or not.
          *
-         * @param {escope.Reference} reference - The reference to check.
+         * @param {eslint-scope.Reference} reference - The reference to check.
          * @returns {boolean} `true` if the reference is 'console'.
          */
         function isConsole(reference) {
@@ -74,7 +74,7 @@ module.exports = {
          * Checks whether the given reference is a member access which is not
          * allowed by options or not.
          *
-         * @param {escope.Reference} reference - The reference to check.
+         * @param {eslint-scope.Reference} reference - The reference to check.
          * @returns {boolean} `true` if the reference is a member access which
          *      is not allowed by options.
          */
@@ -92,7 +92,7 @@ module.exports = {
         /**
          * Reports the given reference as a violation.
          *
-         * @param {escope.Reference} reference - The reference to report.
+         * @param {eslint-scope.Reference} reference - The reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/no-dupe-args.js b/lib/rules/no-dupe-args.js
index cdb38035c..c932be01d 100644
--- a/lib/rules/no-dupe-args.js
+++ b/lib/rules/no-dupe-args.js
@@ -28,7 +28,7 @@ module.exports = {
 
         /**
          * Checks whether or not a given definition is a parameter's.
-         * @param {escope.DefEntry} def - A definition to check.
+         * @param {eslint-scope.DefEntry} def - A definition to check.
          * @returns {boolean} `true` if the definition is a parameter's.
          */
         function isParameter(def) {
diff --git a/lib/rules/no-else-return.js b/lib/rules/no-else-return.js
index 6ba0b2426..68ab4c760 100644
--- a/lib/rules/no-else-return.js
+++ b/lib/rules/no-else-return.js
@@ -9,6 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
+const astUtils = require("../ast-utils");
 const FixTracker = require("../util/fix-tracker");
 
 //------------------------------------------------------------------------------
@@ -199,9 +200,11 @@ module.exports = {
             let consequents,
                 alternate;
 
-            // Only "top-level" if statements are checked, meaning the first `if`
-            // in a `if-else-if-...` chain.
-            if (parent.type === "IfStatement" && parent.alternate === node) {
+            /*
+             * Fixing this would require splitting one statement into two, so no error should
+             * be reported if this node is in a position where only one statement is allowed.
+             */
+            if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
                 return;
             }
 
diff --git a/lib/rules/no-eval.js b/lib/rules/no-eval.js
index fe1456cba..ee5f577f4 100644
--- a/lib/rules/no-eval.js
+++ b/lib/rules/no-eval.js
@@ -166,7 +166,7 @@ module.exports = {
         /**
          * Reports accesses of `eval` via the global object.
          *
-         * @param {escope.Scope} globalScope - The global scope.
+         * @param {eslint-scope.Scope} globalScope - The global scope.
          * @returns {void}
          */
         function reportAccessingEvalViaGlobalObject(globalScope) {
@@ -200,7 +200,7 @@ module.exports = {
         /**
          * Reports all accesses of `eval` (excludes direct calls to eval).
          *
-         * @param {escope.Scope} globalScope - The global scope.
+         * @param {eslint-scope.Scope} globalScope - The global scope.
          * @returns {void}
          */
         function reportAccessingEval(globalScope) {
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 8be8a5a49..bbfae735c 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -60,6 +60,7 @@ module.exports = {
     create(context) {
         const sourceCode = context.getSourceCode();
 
+        const tokensToIgnore = new WeakSet();
         const isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode);
         const precedence = astUtils.getPrecedence;
         const ALL_NODES = context.options[0] !== "functions";
@@ -116,8 +117,8 @@ module.exports = {
                 nextToken = sourceCode.getTokenAfter(node, 1);
 
             return isParenthesised(node) && previousToken && nextToken &&
-                previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
-                nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
+                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
         }
 
         /**
@@ -179,7 +180,7 @@ module.exports = {
             const lastToken = sourceCode.getLastToken(newExpression);
             const penultimateToken = sourceCode.getTokenBefore(lastToken);
 
-            return newExpression.arguments.length > 0 || penultimateToken.value === "(" && lastToken.value === ")";
+            return newExpression.arguments.length > 0 || astUtils.isOpeningParenToken(penultimateToken) && astUtils.isClosingParenToken(lastToken);
         }
 
         /**
@@ -238,69 +239,6 @@ module.exports = {
             return hasDoubleExcessParens(node);
         }
 
-        /**
-         * Checks whether or not a given node is located at the head of ExpressionStatement.
-         * @param {ASTNode} node - A node to check.
-         * @returns {boolean} `true` if the node is located at the head of ExpressionStatement.
-         */
-        function isHeadOfExpressionStatement(node) {
-            let parent = node.parent;
-
-            while (parent) {
-                switch (parent.type) {
-                    case "SequenceExpression":
-                        if (parent.expressions[0] !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "UnaryExpression":
-                    case "UpdateExpression":
-                        if (parent.prefix || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "BinaryExpression":
-                    case "LogicalExpression":
-                        if (parent.left !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "ConditionalExpression":
-                        if (parent.test !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "CallExpression":
-                        if (parent.callee !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "MemberExpression":
-                        if (parent.object !== node || isParenthesised(node)) {
-                            return false;
-                        }
-                        break;
-
-                    case "ExpressionStatement":
-                        return true;
-
-                    default:
-                        return false;
-                }
-
-                node = parent;
-                parent = parent.parent;
-            }
-
-            /* istanbul ignore next */
-            throw new Error("unreachable");
-        }
-
         /**
          * Determines whether a node should be preceded by an additional space when removing parens
          * @param {ASTNode} node node to evaluate; must be surrounded by parentheses
@@ -318,7 +256,7 @@ module.exports = {
             }
 
             // If the parens are preceded by a keyword (e.g. `typeof(0)`), a space should be inserted (`typeof 0`)
-            const precededByKeyword = tokenBeforeLeftParen.type === "Keyword";
+            const precededByIdentiferPart = esUtils.code.isIdentifierPartES6(tokenBeforeLeftParen.value.slice(-1).charCodeAt(0));
 
             // However, a space should not be inserted unless the first character of the token is an identifier part
             // e.g. `typeof([])` should be fixed to `typeof[]`
@@ -331,7 +269,7 @@ module.exports = {
             const startsWithUnaryPlus = firstToken.type === "Punctuator" && firstToken.value === "+";
             const startsWithUnaryMinus = firstToken.type === "Punctuator" && firstToken.value === "-";
 
-            return (precededByKeyword && startsWithIdentifierPart) ||
+            return (precededByIdentiferPart && startsWithIdentifierPart) ||
                 (precededByUnaryPlus && startsWithUnaryPlus) ||
                 (precededByUnaryMinus && startsWithUnaryMinus);
         }
@@ -346,6 +284,10 @@ module.exports = {
             const leftParenToken = sourceCode.getTokenBefore(node);
             const rightParenToken = sourceCode.getTokenAfter(node);
 
+            if (tokensToIgnore.has(sourceCode.getFirstToken(node)) && !isParenthesisedTwice(node)) {
+                return;
+            }
+
             context.report({
                 node,
                 loc: leftParenToken.loc.start,
@@ -466,6 +408,34 @@ module.exports = {
             }
         }
 
+        /**
+         * Checks the parentheses for an ExpressionStatement or ExportDefaultDeclaration
+         * @param {ASTNode} node The ExpressionStatement.expression or ExportDefaultDeclaration.declaration node
+         * @returns {void}
+         */
+        function checkExpressionOrExportStatement(node) {
+            const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node);
+            const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken);
+
+            if (
+                astUtils.isOpeningParenToken(firstToken) &&
+                (
+                    astUtils.isOpeningBraceToken(secondToken) ||
+                    secondToken.type === "Keyword" && (
+                        secondToken.value === "function" ||
+                        secondToken.value === "class" ||
+                        secondToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(secondToken))
+                    )
+                )
+            ) {
+                tokensToIgnore.add(secondToken);
+            }
+
+            if (hasExcessParens(node)) {
+                report(node);
+            }
+        }
+
         return {
             ArrayExpression(node) {
                 [].forEach.call(node.elements, e => {
@@ -481,13 +451,13 @@ module.exports = {
                 }
 
                 if (node.body.type !== "BlockStatement") {
-                    if (sourceCode.getFirstToken(node.body).value !== "{" && hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
-                        report(node.body);
-                        return;
-                    }
+                    const firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken);
+                    const tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken);
 
-                    // Object literals *must* be parenthesised
-                    if (node.body.type === "ObjectExpression" && hasDoubleExcessParens(node.body)) {
+                    if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) {
+                        tokensToIgnore.add(firstBodyToken);
+                    }
+                    if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
                         report(node.body);
                     }
                 }
@@ -530,27 +500,8 @@ module.exports = {
                 }
             },
 
-            ExpressionStatement(node) {
-                if (hasExcessParens(node.expression)) {
-                    const firstTokens = sourceCode.getFirstTokens(node.expression, 2);
-                    const firstToken = firstTokens[0];
-                    const secondToken = firstTokens[1];
-
-                    if (
-                        !firstToken ||
-                        firstToken.value !== "{" &&
-                        firstToken.value !== "function" &&
-                        firstToken.value !== "class" &&
-                        (
-                            firstToken.value !== "let" ||
-                            !secondToken ||
-                            secondToken.value !== "["
-                        )
-                    ) {
-                        report(node.expression);
-                    }
-                }
-            },
+            ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration),
+            ExpressionStatement: node => checkExpressionOrExportStatement(node.expression),
 
             ForInStatement(node) {
                 if (hasExcessParens(node.right)) {
@@ -593,18 +544,11 @@ module.exports = {
                     (
                         node.computed ||
                         !(
-                            (node.object.type === "Literal" &&
-                            typeof node.object.value === "number" &&
-                            astUtils.isDecimalInteger(node.object)) ||
+                            astUtils.isDecimalInteger(node.object) ||
 
                             // RegExp literal is allowed to have parens (#1589)
                             (node.object.type === "Literal" && node.object.regex)
                         )
-                    ) &&
-                    !(
-                        (node.object.type === "FunctionExpression" || node.object.type === "ClassExpression") &&
-                        isHeadOfExpressionStatement(node) &&
-                        !hasDoubleExcessParens(node.object)
                     )
                 ) {
                     report(node.object);
diff --git a/lib/rules/no-extra-semi.js b/lib/rules/no-extra-semi.js
index 2865cdc99..0ec914989 100644
--- a/lib/rules/no-extra-semi.js
+++ b/lib/rules/no-extra-semi.js
@@ -10,6 +10,7 @@
 //------------------------------------------------------------------------------
 
 const FixTracker = require("../util/fix-tracker");
+const astUtils = require("../ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -60,10 +61,10 @@ module.exports = {
          */
         function checkForPartOfClassBody(firstToken) {
             for (let token = firstToken;
-                token.type === "Punctuator" && token.value !== "}";
+                token.type === "Punctuator" && !astUtils.isClosingBraceToken(token);
                 token = sourceCode.getTokenAfter(token)
             ) {
-                if (token.value === ";") {
+                if (astUtils.isSemicolonToken(token)) {
                     report(token);
                 }
             }
diff --git a/lib/rules/no-implicit-coercion.js b/lib/rules/no-implicit-coercion.js
index 8e8db9879..387b3dae4 100644
--- a/lib/rules/no-implicit-coercion.js
+++ b/lib/rules/no-implicit-coercion.js
@@ -6,6 +6,7 @@
 "use strict";
 
 const astUtils = require("../ast-utils");
+const esUtils = require("esutils");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -197,19 +198,31 @@ module.exports = {
         */
         function report(node, recommendation, shouldFix) {
             shouldFix = typeof shouldFix === "undefined" ? true : shouldFix;
-            const reportObj = {
+
+            context.report({
                 node,
                 message: "use `{{recommendation}}` instead.",
                 data: {
                     recommendation
+                },
+                fix(fixer) {
+                    if (!shouldFix) {
+                        return null;
+                    }
+
+                    const tokenBefore = sourceCode.getTokenBefore(node);
+
+                    if (
+                        tokenBefore &&
+                        tokenBefore.range[1] === node.range[0] &&
+                        esUtils.code.isIdentifierPartES6(tokenBefore.value.slice(-1).charCodeAt(0)) &&
+                        esUtils.code.isIdentifierPartES6(recommendation.charCodeAt(0))
+                    ) {
+                        return fixer.replaceText(node, ` ${recommendation}`);
+                    }
+                    return fixer.replaceText(node, recommendation);
                 }
-            };
-
-            if (shouldFix) {
-                reportObj.fix = fixer => fixer.replaceText(node, recommendation);
-            }
-
-            context.report(reportObj);
+            });
         }
 
         return {
diff --git a/lib/rules/no-loop-func.js b/lib/rules/no-loop-func.js
index b8bed9586..df0f17678 100644
--- a/lib/rules/no-loop-func.js
+++ b/lib/rules/no-loop-func.js
@@ -90,7 +90,7 @@ function getTopLoopNode(node, excludedNode) {
  *
  * @param {ASTNode} funcNode - A target function node.
  * @param {ASTNode} loopNode - A containing loop node.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is safe or not.
  */
 function isSafe(funcNode, loopNode, reference) {
@@ -131,7 +131,7 @@ function isSafe(funcNode, loopNode, reference) {
      * - is readonly.
      * - doesn't exist inside a local function and after the border.
      *
-     * @param {escope.Reference} upperRef - A reference to check.
+     * @param {eslint-scope.Reference} upperRef - A reference to check.
      * @returns {boolean} `true` if the reference is safe.
      */
     function isSafeReference(upperRef) {
diff --git a/lib/rules/no-native-reassign.js b/lib/rules/no-native-reassign.js
index f721fc278..d3dfefbaf 100644
--- a/lib/rules/no-native-reassign.js
+++ b/lib/rules/no-native-reassign.js
@@ -15,7 +15,7 @@ module.exports = {
         docs: {
             description: "disallow assignments to native objects or read-only global variables",
             category: "Best Practices",
-            recommended: true,
+            recommended: false,
             replacedBy: ["no-global-assign"]
         },
 
diff --git a/lib/rules/no-negated-in-lhs.js b/lib/rules/no-negated-in-lhs.js
index 143518060..495cbc160 100644
--- a/lib/rules/no-negated-in-lhs.js
+++ b/lib/rules/no-negated-in-lhs.js
@@ -15,7 +15,7 @@ module.exports = {
         docs: {
             description: "disallow negating the left operand in `in` expressions",
             category: "Possible Errors",
-            recommended: true,
+            recommended: false,
             replacedBy: ["no-unsafe-negation"]
         },
         deprecated: true,
diff --git a/lib/rules/no-param-reassign.js b/lib/rules/no-param-reassign.js
index f8f6d1263..560d1d6b6 100644
--- a/lib/rules/no-param-reassign.js
+++ b/lib/rules/no-param-reassign.js
@@ -96,8 +96,15 @@ module.exports = {
                         }
                         break;
 
-                    default:
+                    // EXCLUDES: e.g. ({ [foo]: a }) = bar;
+                    case "Property":
+                        if (parent.key === node) {
+                            return false;
+                        }
+
                         break;
+
+                    // no default
                 }
 
                 node = parent;
diff --git a/lib/rules/no-redeclare.js b/lib/rules/no-redeclare.js
index bfbc09ffb..ccb57003e 100644
--- a/lib/rules/no-redeclare.js
+++ b/lib/rules/no-redeclare.js
@@ -35,7 +35,7 @@ module.exports = {
 
         /**
          * Find variables in a given scope and flag redeclared ones.
-         * @param {Scope} scope - An escope scope object.
+         * @param {Scope} scope - An eslint-scope scope object.
          * @returns {void}
          * @private
          */
diff --git a/lib/rules/no-restricted-syntax.js b/lib/rules/no-restricted-syntax.js
index d87e589c7..1798065ec 100644
--- a/lib/rules/no-restricted-syntax.js
+++ b/lib/rules/no-restricted-syntax.js
@@ -18,18 +18,45 @@ module.exports = {
 
         schema: {
             type: "array",
-            items: [{ type: "string" }],
+            items: [{
+                oneOf: [
+                    {
+                        type: "string"
+                    },
+                    {
+                        type: "object",
+                        properties: {
+                            selector: { type: "string" },
+                            message: { type: "string" }
+                        },
+                        required: ["selector"],
+                        additionalProperties: false
+                    }
+                ]
+            }],
             uniqueItems: true,
             minItems: 0
         }
     },
 
     create(context) {
-        return context.options.reduce((result, selector) => Object.assign(result, {
-            [selector](node) {
-                context.report({ node, message: "Using '{{selector}}' is not allowed.", data: { selector } });
-            }
-        }), {});
+        return context.options.reduce((result, selectorOrObject) => {
+            const isStringFormat = (typeof selectorOrObject === "string");
+            const hasCustomMessage = !isStringFormat && Boolean(selectorOrObject.message);
+
+            const selector = isStringFormat ? selectorOrObject : selectorOrObject.selector;
+            const message = hasCustomMessage ? selectorOrObject.message : "Using '{{selector}}' is not allowed.";
+
+            return Object.assign(result, {
+                [selector](node) {
+                    context.report({
+                        node,
+                        message,
+                        data: hasCustomMessage ? {} : { selector }
+                    });
+                }
+            });
+        }, {});
 
     }
 };
diff --git a/lib/rules/no-sequences.js b/lib/rules/no-sequences.js
index ff582bd1d..23c1956eb 100644
--- a/lib/rules/no-sequences.js
+++ b/lib/rules/no-sequences.js
@@ -76,8 +76,8 @@ module.exports = {
                 nextToken = sourceCode.getTokenAfter(node, 1);
 
             return isParenthesised(node) && previousToken && nextToken &&
-                previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
-                nextToken.value === ")" && nextToken.range[0] >= node.range[1];
+                astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
+                astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
         }
 
         return {
diff --git a/lib/rules/no-undefined.js b/lib/rules/no-undefined.js
index d29ac1e72..7e9f96b92 100644
--- a/lib/rules/no-undefined.js
+++ b/lib/rules/no-undefined.js
@@ -36,7 +36,7 @@ module.exports = {
         /**
          * Checks the given scope for references to `undefined` and reports
          * all references found.
-         * @param {escope.Scope} scope The scope to check.
+         * @param {eslint-scope.Scope} scope The scope to check.
          * @returns {void}
          */
         function checkScope(scope) {
diff --git a/lib/rules/no-unmodified-loop-condition.js b/lib/rules/no-unmodified-loop-condition.js
index 824361191..41d93d8af 100644
--- a/lib/rules/no-unmodified-loop-condition.js
+++ b/lib/rules/no-unmodified-loop-condition.js
@@ -25,7 +25,7 @@ const DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/;
 
 /**
  * @typedef {Object} LoopConditionInfo
- * @property {escope.Reference} reference - The reference.
+ * @property {eslint-scope.Reference} reference - The reference.
  * @property {ASTNode} group - BinaryExpression or ConditionalExpression nodes
  *      that the reference is belonging to.
  * @property {Function} isInLoop - The predicate which checks a given reference
@@ -37,7 +37,7 @@ const DYNAMIC_PATTERN = /^(?:Call|Member|New|TaggedTemplate|Yield)Expression$/;
 /**
  * Checks whether or not a given reference is a write reference.
  *
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is a write reference.
  */
 function isWriteReference(reference) {
@@ -77,7 +77,7 @@ function isUnmodifiedAndNotBelongToGroup(condition) {
  * Checks whether or not a given reference is inside of a given node.
  *
  * @param {ASTNode} node - A node to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is inside of the node.
  */
 function isInRange(node, reference) {
@@ -91,7 +91,7 @@ function isInRange(node, reference) {
  * Checks whether or not a given reference is inside of a loop node's condition.
  *
  * @param {ASTNode} node - A node to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the reference is inside of the loop node's
  *      condition.
  */
@@ -134,7 +134,7 @@ function hasDynamicExpressions(root) {
 /**
  * Creates the loop condition information from a given reference.
  *
- * @param {escope.Reference} reference - A reference to create.
+ * @param {eslint-scope.Reference} reference - A reference to create.
  * @returns {LoopConditionInfo|null} Created loop condition info, or null.
  */
 function toLoopCondition(reference) {
@@ -188,7 +188,7 @@ function toLoopCondition(reference) {
  * Gets the function which encloses a given reference.
  * This supports only FunctionDeclaration.
  *
- * @param {escope.Reference} reference - A reference to get.
+ * @param {eslint-scope.Reference} reference - A reference to get.
  * @returns {ASTNode|null} The function node or null.
  */
 function getEncloseFunctionDeclaration(reference) {
@@ -209,7 +209,7 @@ function getEncloseFunctionDeclaration(reference) {
  * Updates the "modified" flags of given loop conditions with given modifiers.
  *
  * @param {LoopConditionInfo[]} conditions - The loop conditions to be updated.
- * @param {escope.Reference[]} modifiers - The references to update.
+ * @param {eslint-scope.Reference[]} modifiers - The references to update.
  * @returns {void}
  */
 function updateModifiedFlag(conditions, modifiers) {
@@ -311,7 +311,7 @@ module.exports = {
          * Finds unmodified references which are inside of a loop condition.
          * Then reports the references which are outside of groups.
          *
-         * @param {escope.Variable} variable - A variable to report.
+         * @param {eslint-scope.Variable} variable - A variable to report.
          * @returns {void}
          */
         function checkReferences(variable) {
diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js
index 4e2378d4d..761dc0338 100644
--- a/lib/rules/no-unsafe-negation.js
+++ b/lib/rules/no-unsafe-negation.js
@@ -44,7 +44,7 @@ module.exports = {
         docs: {
             description: "disallow negating the left operand of relational operators",
             category: "Possible Errors",
-            recommended: false
+            recommended: true
         },
         schema: [],
         fixable: "code"
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 6f2703967..3ff9bc64f 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -108,7 +108,7 @@ module.exports = {
 
         /**
          * Determines if a given variable is being exported from a module.
-         * @param {Variable} variable - EScope variable object.
+         * @param {Variable} variable - eslint-scope variable object.
          * @returns {boolean} True if the variable is exported, false if not.
          * @private
          */
@@ -134,7 +134,7 @@ module.exports = {
 
         /**
          * Determines if a variable has a sibling rest property
-         * @param {Variable} variable - EScope variable object.
+         * @param {Variable} variable - eslint-scope variable object.
          * @returns {boolean} True if the variable is exported, false if not.
          * @private
          */
@@ -157,7 +157,7 @@ module.exports = {
 
         /**
          * Determines if a reference is a read operation.
-         * @param {Reference} ref - An escope Reference
+         * @param {Reference} ref - An eslint-scope Reference
          * @returns {boolean} whether the given reference represents a read operation
          * @private
          */
@@ -212,7 +212,7 @@ module.exports = {
          * - The reference is inside of a function scope which is different from
          *   the declaration.
          *
-         * @param {escope.Reference} ref - A reference to check.
+         * @param {eslint-scope.Reference} ref - A reference to check.
          * @param {ASTNode} prevRhsNode - The previous RHS node.
          * @returns {ASTNode|null} The RHS node or null.
          * @private
@@ -322,7 +322,7 @@ module.exports = {
         /**
          * Checks whether a given reference is a read to update itself or not.
          *
-         * @param {escope.Reference} ref - A reference to check.
+         * @param {eslint-scope.Reference} ref - A reference to check.
          * @param {ASTNode} rhsNode - The RHS node of the previous assignment.
          * @returns {boolean} The reference is a read to update itself.
          * @private
@@ -422,7 +422,7 @@ module.exports = {
         /**
          * Checks whether the given variable is the last parameter in the non-ignored parameters.
          *
-         * @param {escope.Variable} variable - The variable to check.
+         * @param {eslint-scope.Variable} variable - The variable to check.
          * @returns {boolean} `true` if the variable is the last.
          */
         function isLastInNonIgnoredParameters(variable) {
@@ -448,7 +448,7 @@ module.exports = {
 
         /**
          * Gets an array of variables without read references.
-         * @param {Scope} scope - an escope Scope object.
+         * @param {Scope} scope - an eslint-scope Scope object.
          * @param {Variable[]} unusedVars - an array that saving result.
          * @returns {Variable[]} unused variables of the scope and descendant scopes.
          * @private
@@ -540,7 +540,7 @@ module.exports = {
 
         /**
          * Gets the index of a given variable name in a given comment.
-         * @param {escope.Variable} variable - A variable to get.
+         * @param {eslint-scope.Variable} variable - A variable to get.
          * @param {ASTNode} comment - A comment node which includes the variable name.
          * @returns {number} The index of the variable name's location.
          * @private
@@ -561,7 +561,7 @@ module.exports = {
          * Creates the correct location of a given variables.
          * The location is at its name string in a `/*global` comment.
          *
-         * @param {escope.Variable} variable - A variable to get its location.
+         * @param {eslint-scope.Variable} variable - A variable to get its location.
          * @returns {{line: number, column: number}} The location object for the variable.
          * @private
          */
diff --git a/lib/rules/no-use-before-define.js b/lib/rules/no-use-before-define.js
index 1a779b86f..6d01e3e10 100644
--- a/lib/rules/no-use-before-define.js
+++ b/lib/rules/no-use-before-define.js
@@ -37,7 +37,7 @@ function parseOptions(options) {
 /**
  * Checks whether or not a given variable is a function declaration.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function declaration.
  */
 function isFunction(variable) {
@@ -47,8 +47,8 @@ function isFunction(variable) {
 /**
  * Checks whether or not a given variable is a class declaration in an upper function scope.
  *
- * @param {escope.Variable} variable - A variable to check.
- * @param {escope.Reference} reference - A reference to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Reference} reference - A reference to check.
  * @returns {boolean} `true` if the variable is a class declaration.
  */
 function isOuterClass(variable, reference) {
@@ -60,8 +60,8 @@ function isOuterClass(variable, reference) {
 
 /**
 * Checks whether or not a given variable is a variable declaration in an upper function scope.
-* @param {escope.Variable} variable - A variable to check.
-* @param {escope.Reference} reference - A reference to check.
+* @param {eslint-scope.Variable} variable - A variable to check.
+* @param {eslint-scope.Reference} reference - A reference to check.
 * @returns {boolean} `true` if the variable is a variable declaration.
 */
 function isOuterVariable(variable, reference) {
@@ -167,8 +167,8 @@ module.exports = {
 
         /**
          * Determines whether a given use-before-define case should be reported according to the options.
-         * @param {escope.Variable} variable The variable that gets used before being defined
-         * @param {escope.Reference} reference The reference to the variable
+         * @param {eslint-scope.Variable} variable The variable that gets used before being defined
+         * @param {eslint-scope.Reference} reference The reference to the variable
          * @returns {boolean} `true` if the usage should be reported
          */
         function isForbidden(variable, reference) {
diff --git a/lib/rules/no-useless-computed-key.js b/lib/rules/no-useless-computed-key.js
index 573fe21c0..fd5ec2c92 100644
--- a/lib/rules/no-useless-computed-key.js
+++ b/lib/rules/no-useless-computed-key.js
@@ -9,6 +9,7 @@
 //------------------------------------------------------------------------------
 
 const astUtils = require("../ast-utils");
+const esUtils = require("esutils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -55,7 +56,17 @@ module.exports = {
                                 // If there are comments between the brackets and the property name, don't do a fix.
                                 return null;
                             }
-                            return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], key.raw);
+
+                            const tokenBeforeLeftBracket = sourceCode.getTokenBefore(leftSquareBracket);
+
+                            // Insert a space before the key to avoid changing identifiers, e.g. ({ get[2]() {} }) to ({ get2() {} })
+                            const needsSpaceBeforeKey = tokenBeforeLeftBracket.range[1] === leftSquareBracket.range[0] &&
+                                esUtils.code.isIdentifierPartES6(tokenBeforeLeftBracket.value.slice(-1).charCodeAt(0)) &&
+                                esUtils.code.isIdentifierPartES6(key.raw.charCodeAt(0));
+
+                            const replacementKey = (needsSpaceBeforeKey ? " " : "") + key.raw;
+
+                            return fixer.replaceTextRange([leftSquareBracket.range[0], rightSquareBracket.range[1]], replacementKey);
                         }
                     });
                 }
diff --git a/lib/rules/no-var.js b/lib/rules/no-var.js
index 86373ad50..c74e0b9ad 100644
--- a/lib/rules/no-var.js
+++ b/lib/rules/no-var.js
@@ -19,8 +19,8 @@ const astUtils = require("../ast-utils");
  * Finds the nearest function scope or global scope walking up the scope
  * hierarchy.
  *
- * @param {escope.Scope} scope - The scope to traverse.
- * @returns {escope.Scope} a function scope or global scope containing the given
+ * @param {eslint-scope.Scope} scope - The scope to traverse.
+ * @returns {eslint-scope.Scope} a function scope or global scope containing the given
  *      scope.
  */
 function getEnclosingFunctionScope(scope) {
@@ -34,7 +34,7 @@ function getEnclosingFunctionScope(scope) {
  * Checks whether the given variable has any references from a more specific
  * function expression (i.e. a closure).
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is used from a closure.
  */
 function isReferencedInClosure(variable) {
@@ -93,7 +93,7 @@ function getScopeNode(node) {
 /**
  * Checks whether a given variable is redeclared or not.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is redeclared.
  */
 function isRedeclared(variable) {
@@ -112,7 +112,7 @@ function isUsedFromOutsideOf(scopeNode) {
     /**
      * Checks whether a given reference is inside of the specified scope or not.
      *
-     * @param {escope.Reference} reference - A reference to check.
+     * @param {eslint-scope.Reference} reference - A reference to check.
      * @returns {boolean} `true` if the reference is inside of the specified
      *      scope.
      */
diff --git a/lib/rules/object-curly-spacing.js b/lib/rules/object-curly-spacing.js
index 8971aff8a..5c885240e 100644
--- a/lib/rules/object-curly-spacing.js
+++ b/lib/rules/object-curly-spacing.js
@@ -171,8 +171,8 @@ module.exports = {
 
             if (astUtils.isTokenOnSameLine(penultimate, last)) {
                 const shouldCheckPenultimate = (
-                    options.arraysInObjectsException && penultimate.value === "]" ||
-                    options.objectsInObjectsException && penultimate.value === "}"
+                    options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) ||
+                    options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate)
                 );
                 const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.start).type;
 
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index 1d32d1722..1d3d9dae1 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -230,7 +230,10 @@ module.exports = {
                 const functionToken = sourceCode.getTokens(node.value).find(token => token.type === "Keyword" && token.value === "function");
                 const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken;
 
-                return fixer.replaceTextRange([firstKeyToken.range[0], tokenBeforeParams.range[1]], keyPrefix + keyText);
+                return fixer.replaceTextRange(
+                    [firstKeyToken.range[0], node.range[1]],
+                    keyPrefix + keyText + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1])
+                );
             }
             const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
             const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
@@ -238,7 +241,10 @@ module.exports = {
             const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
             const newParamText = hasParensAroundParameters ? oldParamText : `(${oldParamText})`;
 
-            return fixer.replaceTextRange([firstKeyToken.range[0], arrowToken.range[1]], keyPrefix + keyText + newParamText);
+            return fixer.replaceTextRange(
+                [firstKeyToken.range[0], node.range[1]],
+                keyPrefix + keyText + newParamText + sourceCode.text.slice(arrowToken.range[1], node.value.range[1])
+            );
 
         }
 
diff --git a/lib/rules/operator-assignment.js b/lib/rules/operator-assignment.js
index 43f21abc8..99cca356f 100644
--- a/lib/rules/operator-assignment.js
+++ b/lib/rules/operator-assignment.js
@@ -4,6 +4,12 @@
  */
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("../ast-utils");
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
@@ -135,7 +141,7 @@ module.exports = {
                                 const equalsToken = getOperatorToken(node);
                                 const operatorToken = getOperatorToken(expr);
                                 const leftText = sourceCode.getText().slice(node.range[0], equalsToken.range[0]);
-                                const rightText = sourceCode.getText().slice(operatorToken.range[1], expr.right.range[1]);
+                                const rightText = sourceCode.getText().slice(operatorToken.range[1], node.right.range[1]);
 
                                 return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
                             }
@@ -171,9 +177,20 @@ module.exports = {
                         if (canBeFixed(node.left)) {
                             const operatorToken = getOperatorToken(node);
                             const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
-                            const rightText = sourceCode.getText().slice(operatorToken.range[1], node.range[1]);
+                            const newOperator = node.operator.slice(0, -1);
+                            let rightText;
+
+                            // If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
+                            if (
+                                astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
+                                !astUtils.isParenthesised(sourceCode, node.right)
+                            ) {
+                                rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
+                            } else {
+                                rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
+                            }
 
-                            return fixer.replaceText(node, `${leftText}= ${leftText}${node.operator.slice(0, -1)}${rightText}`);
+                            return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
                         }
                         return null;
                     }
diff --git a/lib/rules/padded-blocks.js b/lib/rules/padded-blocks.js
index 36036aec4..a485c1770 100644
--- a/lib/rules/padded-blocks.js
+++ b/lib/rules/padded-blocks.js
@@ -51,7 +51,11 @@ module.exports = {
         const config = context.options[0] || "always";
 
         if (typeof config === "string") {
-            options.blocks = config === "always";
+            const shouldHavePadding = config === "always";
+
+            options.blocks = shouldHavePadding;
+            options.switches = shouldHavePadding;
+            options.classes = shouldHavePadding;
         } else {
             if (config.hasOwnProperty("blocks")) {
                 options.blocks = config.blocks === "always";
diff --git a/lib/rules/prefer-arrow-callback.js b/lib/rules/prefer-arrow-callback.js
index ee385042f..b9cde17ca 100644
--- a/lib/rules/prefer-arrow-callback.js
+++ b/lib/rules/prefer-arrow-callback.js
@@ -11,7 +11,7 @@
 
 /**
  * Checks whether or not a given variable is a function name.
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is a function name.
  */
 function isFunctionName(variable) {
@@ -31,8 +31,8 @@ function checkMetaProperty(node, metaName, propertyName) {
 
 /**
  * Gets the variable object of `arguments` which is defined implicitly.
- * @param {escope.Scope} scope - A scope to get.
- * @returns {escope.Variable} The found variable object.
+ * @param {eslint-scope.Scope} scope - A scope to get.
+ * @returns {eslint-scope.Variable} The found variable object.
  */
 function getVariableOfArguments(scope) {
     const variables = scope.variables;
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index 07d8da82a..595bb8a53 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -9,7 +9,7 @@
 // Helpers
 //------------------------------------------------------------------------------
 
-const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|Property)$/;
+const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/;
 const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/;
 const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/;
 
@@ -73,7 +73,7 @@ function canBecomeVariableDeclaration(identifier) {
  *   warn such variables because this rule cannot distinguish whether the
  *   exported variables are reassigned or not.
  *
- * @param {escope.Variable} variable - A variable to get.
+ * @param {eslint-scope.Variable} variable - A variable to get.
  * @param {boolean} ignoreReadBeforeAssign -
  *      The value of `ignoreReadBeforeAssign` option.
  * @returns {ASTNode|null}
@@ -146,7 +146,7 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
  * This is used to detect a mix of reassigned and never reassigned in a
  * destructuring.
  *
- * @param {escope.Reference} reference - A reference to get.
+ * @param {eslint-scope.Reference} reference - A reference to get.
  * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
  *      null.
  */
@@ -172,7 +172,7 @@ function getDestructuringHost(reference) {
  * This is used to detect a mix of reassigned and never reassigned in a
  * destructuring.
  *
- * @param {escope.Variable[]} variables - Variables to group by destructuring.
+ * @param {eslint-scope.Variable[]} variables - Variables to group by destructuring.
  * @param {boolean} ignoreReadBeforeAssign -
  *      The value of `ignoreReadBeforeAssign` option.
  * @returns {Map<ASTNode, ASTNode[]>} Grouped identifier nodes.
@@ -274,7 +274,7 @@ module.exports = {
          * the array is 1. In destructuring cases, the length of the array can
          * be 2 or more.
          *
-         * @param {(escope.Reference|null)[]} nodes -
+         * @param {(eslint-scope.Reference|null)[]} nodes -
          *      References which are grouped by destructuring to report.
          * @returns {void}
          */
diff --git a/lib/rules/prefer-rest-params.js b/lib/rules/prefer-rest-params.js
index a9db624dc..d55d5dad0 100644
--- a/lib/rules/prefer-rest-params.js
+++ b/lib/rules/prefer-rest-params.js
@@ -11,8 +11,8 @@
 
 /**
  * Gets the variable object of `arguments` which is defined implicitly.
- * @param {escope.Scope} scope - A scope to get.
- * @returns {escope.Variable} The found variable object.
+ * @param {eslint-scope.Scope} scope - A scope to get.
+ * @returns {eslint-scope.Variable} The found variable object.
  */
 function getVariableOfArguments(scope) {
     const variables = scope.variables;
@@ -40,7 +40,7 @@ function getVariableOfArguments(scope) {
  * - arguments[0]      .... true    // computed member access
  * - arguments.length  .... false   // normal member access
  *
- * @param {escope.Reference} reference - The reference to check.
+ * @param {eslint-scope.Reference} reference - The reference to check.
  * @returns {boolean} `true` if the reference is not normal member access.
  */
 function isNotNormalMemberAccess(reference) {
@@ -74,7 +74,7 @@ module.exports = {
         /**
          * Reports a given reference.
          *
-         * @param {escope.Reference} reference - A reference to report.
+         * @param {eslint-scope.Reference} reference - A reference to report.
          * @returns {void}
          */
         function report(reference) {
diff --git a/lib/rules/quotes.js b/lib/rules/quotes.js
index 1085ea33b..b1117b85f 100644
--- a/lib/rules/quotes.js
+++ b/lib/rules/quotes.js
@@ -209,6 +209,7 @@ module.exports = {
 
                 // LiteralPropertyName.
                 case "Property":
+                case "MethodDefinition":
                     return parent.key === node && !parent.computed;
 
                 // ModuleSpecifier.
diff --git a/lib/rules/radix.js b/lib/rules/radix.js
index 0dfa081b6..0484c3bfb 100644
--- a/lib/rules/radix.js
+++ b/lib/rules/radix.js
@@ -21,7 +21,7 @@ const MODE_ALWAYS = "always",
 /**
  * Checks whether a given variable is shadowed or not.
  *
- * @param {escope.Variable} variable - A variable to check.
+ * @param {eslint-scope.Variable} variable - A variable to check.
  * @returns {boolean} `true` if the variable is shadowed.
  */
 function isShadowed(variable) {
diff --git a/lib/rules/semi-spacing.js b/lib/rules/semi-spacing.js
index 854abbe39..fd300e4a3 100644
--- a/lib/rules/semi-spacing.js
+++ b/lib/rules/semi-spacing.js
@@ -105,20 +105,7 @@ module.exports = {
         function isBeforeClosingParen(token) {
             const nextToken = sourceCode.getTokenAfter(token);
 
-            return (
-                nextToken &&
-                nextToken.type === "Punctuator" &&
-                (nextToken.value === "}" || nextToken.value === ")")
-            );
-        }
-
-        /**
-         * Checks if the given token is a semicolon.
-         * @param {Token} token The token to check.
-         * @returns {boolean} Whether or not the given token is a semicolon.
-         */
-        function isSemicolon(token) {
-            return token.type === "Punctuator" && token.value === ";";
+            return (nextToken && astUtils.isClosingBraceToken(nextToken) || astUtils.isClosingParenToken(nextToken));
         }
 
         /**
@@ -128,7 +115,7 @@ module.exports = {
          * @returns {void}
          */
         function checkSemicolonSpacing(token, node) {
-            if (isSemicolon(token)) {
+            if (astUtils.isSemicolonToken(token)) {
                 const location = token.loc.start;
 
                 if (hasLeadingSpace(token)) {
diff --git a/lib/rules/semi.js b/lib/rules/semi.js
index 8fd43f768..0bfdff110 100644
--- a/lib/rules/semi.js
+++ b/lib/rules/semi.js
@@ -9,6 +9,7 @@
 //------------------------------------------------------------------------------
 
 const FixTracker = require("../util/fix-tracker");
+const astUtils = require("../ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -110,15 +111,6 @@ module.exports = {
 
         }
 
-        /**
-         * Checks whether a token is a semicolon punctuator.
-         * @param {Token} token The token.
-         * @returns {boolean} True if token is a semicolon punctuator.
-         */
-        function isSemicolon(token) {
-            return (token.type === "Punctuator" && token.value === ";");
-        }
-
         /**
          * Check if a semicolon is unnecessary, only true if:
          *   - next token is on a new line and is not one of the opt-out tokens
@@ -127,7 +119,7 @@ module.exports = {
          * @returns {boolean} whether the semicolon is unnecessary.
          */
         function isUnnecessarySemicolon(lastToken) {
-            if (!isSemicolon(lastToken)) {
+            if (!astUtils.isSemicolonToken(lastToken)) {
                 return false;
             }
 
@@ -140,7 +132,7 @@ module.exports = {
             const lastTokenLine = lastToken.loc.end.line;
             const nextTokenLine = nextToken.loc.start.line;
             const isOptOutToken = OPT_OUT_PATTERN.test(nextToken.value) && nextToken.value !== "++" && nextToken.value !== "--";
-            const isDivider = (nextToken.value === "}" || nextToken.value === ";");
+            const isDivider = (astUtils.isClosingBraceToken(nextToken) || astUtils.isSemicolonToken(nextToken));
 
             return (lastTokenLine !== nextTokenLine && !isOptOutToken) || isDivider;
         }
@@ -176,7 +168,7 @@ module.exports = {
                     report(node, true);
                 }
             } else {
-                if (!isSemicolon(lastToken)) {
+                if (!astUtils.isSemicolonToken(lastToken)) {
                     if (!exceptOneLine || !isOneLinerBlock(node)) {
                         report(node);
                     }
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index fe2466ea8..53aac71ed 100644
--- a/lib/rules/space-before-function-paren.js
+++ b/lib/rules/space-before-function-paren.js
@@ -51,31 +51,9 @@ module.exports = {
     },
 
     create(context) {
-
-        const configuration = context.options[0],
-            sourceCode = context.getSourceCode();
-        let requireAnonymousFunctionSpacing = true,
-            forbidAnonymousFunctionSpacing = false,
-            requireNamedFunctionSpacing = true,
-            forbidNamedFunctionSpacing = false,
-            requireArrowFunctionSpacing = false,
-            forbidArrowFunctionSpacing = false;
-
-        if (typeof configuration === "object") {
-            requireAnonymousFunctionSpacing = (
-                !configuration.anonymous || configuration.anonymous === "always");
-            forbidAnonymousFunctionSpacing = configuration.anonymous === "never";
-            requireNamedFunctionSpacing = (
-                !configuration.named || configuration.named === "always");
-            forbidNamedFunctionSpacing = configuration.named === "never";
-            requireArrowFunctionSpacing = configuration.asyncArrow === "always";
-            forbidArrowFunctionSpacing = configuration.asyncArrow === "never";
-        } else if (configuration === "never") {
-            requireAnonymousFunctionSpacing = false;
-            forbidAnonymousFunctionSpacing = true;
-            requireNamedFunctionSpacing = false;
-            forbidNamedFunctionSpacing = true;
-        }
+        const sourceCode = context.getSourceCode();
+        const baseConfig = typeof context.options[0] === "string" ? context.options[0] : "always";
+        const overrideConfig = typeof context.options[0] === "object" ? context.options[0] : {};
 
         /**
          * Determines whether a function has a name.
@@ -100,69 +78,67 @@ module.exports = {
         }
 
         /**
-         * Validates the spacing before function parentheses.
-         * @param {ASTNode} node The node to be validated.
-         * @returns {void}
+         * Gets the config for a given function
+         * @param {ASTNode} node The function node
+         * @returns {string} "always", "never", or "ignore"
          */
-        function validateSpacingBeforeParentheses(node) {
-            const isArrow = node.type === "ArrowFunctionExpression";
-            const isNamed = !isArrow && isNamedFunction(node);
-            const isAnonymousGenerator = node.generator && !isNamed;
-            const isNormalArrow = isArrow && !node.async;
-            const isArrowWithoutParens = isArrow && sourceCode.getFirstToken(node, 1).value !== "(";
-            let forbidSpacing, requireSpacing;
-
-            // isAnonymousGenerator → `generator-star-spacing` should warn it. E.g. `function* () {}`
-            // isNormalArrow → ignore always.
-            // isArrowWithoutParens → ignore always. E.g. `async a => a`
-            if (isAnonymousGenerator || isNormalArrow || isArrowWithoutParens) {
-                return;
+        function getConfigForFunction(node) {
+            if (node.type === "ArrowFunctionExpression") {
+
+                // Always ignore non-async functions and arrow functions without parens, e.g. async foo => bar
+                if (node.async && astUtils.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 }))) {
+
+                    // For backwards compatibility, the base config does not apply to async arrow functions.
+                    return overrideConfig.asyncArrow || "ignore";
+                }
+            } else if (isNamedFunction(node)) {
+                return overrideConfig.named || baseConfig;
+
+            // `generator-star-spacing` should warn anonymous generators. E.g. `function* () {}`
+            } else if (!node.generator) {
+                return overrideConfig.anonymous || baseConfig;
             }
 
-            if (isArrow) {
-                forbidSpacing = forbidArrowFunctionSpacing;
-                requireSpacing = requireArrowFunctionSpacing;
-            } else if (isNamed) {
-                forbidSpacing = forbidNamedFunctionSpacing;
-                requireSpacing = requireNamedFunctionSpacing;
-            } else {
-                forbidSpacing = forbidAnonymousFunctionSpacing;
-                requireSpacing = requireAnonymousFunctionSpacing;
+            return "ignore";
+        }
+
+        /**
+         * Checks the parens of a function node
+         * @param {ASTNode} node A function node
+         * @returns {void}
+         */
+        function checkFunction(node) {
+            const functionConfig = getConfigForFunction(node);
+
+            if (functionConfig === "ignore") {
+                return;
             }
 
             const rightToken = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
             const leftToken = sourceCode.getTokenBefore(rightToken);
-            const location = leftToken.loc.end;
-
-            if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
-                if (forbidSpacing) {
-                    context.report({
-                        node,
-                        loc: location,
-                        message: "Unexpected space before function parentheses.",
-                        fix(fixer) {
-                            return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
-                        }
-                    });
-                }
-            } else {
-                if (requireSpacing) {
-                    context.report({
-                        node,
-                        loc: location,
-                        message: "Missing space before function parentheses.",
-                        fix(fixer) {
-                            return fixer.insertTextAfter(leftToken, " ");
-                        }
-                    });
-                }
+            const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken);
+
+            if (hasSpacing && functionConfig === "never") {
+                context.report({
+                    node,
+                    loc: leftToken.loc.end,
+                    message: "Unexpected space before function parentheses.",
+                    fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
+                });
+            } else if (!hasSpacing && functionConfig === "always") {
+                context.report({
+                    node,
+                    loc: leftToken.loc.end,
+                    message: "Missing space before function parentheses.",
+                    fix: fixer => fixer.insertTextAfter(leftToken, " ")
+                });
             }
         }
 
         return {
-            FunctionDeclaration: validateSpacingBeforeParentheses,
-            FunctionExpression: validateSpacingBeforeParentheses,
-            ArrowFunctionExpression: validateSpacingBeforeParentheses
+            ArrowFunctionExpression: checkFunction,
+            FunctionDeclaration: checkFunction,
+            FunctionExpression: checkFunction
         };
     }
 };
diff --git a/lib/rules/space-in-parens.js b/lib/rules/space-in-parens.js
index c0850b9db..95b03c3db 100644
--- a/lib/rules/space-in-parens.js
+++ b/lib/rules/space-in-parens.js
@@ -128,7 +128,7 @@ module.exports = {
             }
 
             if (ALWAYS) {
-                if (right.type === "Punctuator" && right.value === ")") {
+                if (astUtils.isClosingParenToken(right)) {
                     return false;
                 }
                 return !isOpenerException(right);
@@ -144,7 +144,7 @@ module.exports = {
          * @returns {boolean} True if the paren should have a space
          */
         function shouldCloserHaveSpace(left, right) {
-            if (left.type === "Punctuator" && left.value === "(") {
+            if (astUtils.isOpeningParenToken(left)) {
                 return false;
             }
 
@@ -192,7 +192,7 @@ module.exports = {
          * @returns {boolean} True if the paren should reject the space
          */
         function shouldCloserRejectSpace(left, right) {
-            if (left.type === "Punctuator" && left.value === "(") {
+            if (astUtils.isOpeningParenToken(left)) {
                 return false;
             }
 
@@ -224,11 +224,7 @@ module.exports = {
                     const prevToken = tokens[i - 1];
                     const nextToken = tokens[i + 1];
 
-                    if (token.type !== "Punctuator") {
-                        return;
-                    }
-
-                    if (token.value !== "(" && token.value !== ")") {
+                    if (!astUtils.isOpeningParenToken(token) && !astUtils.isClosingParenToken(token)) {
                         return;
                     }
 
diff --git a/lib/util/glob-util.js b/lib/util/glob-util.js
index d414f783f..4c21fc551 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-util.js
@@ -86,7 +86,7 @@ function resolveFileGlobPatterns(patterns, options) {
 
     const processPathExtensions = processPath(options);
 
-    return patterns.map(processPathExtensions);
+    return patterns.filter(p => p.length).map(processPathExtensions);
 }
 
 /**
diff --git a/package.json b/package.json
index 0b14bf07f..eafb1cdd3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "3.18.0",
+  "version": "3.19.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -39,7 +39,7 @@
     "concat-stream": "^1.5.2",
     "debug": "^2.1.1",
     "doctrine": "^2.0.0",
-    "escope": "^3.6.0",
+    "eslint-scope": "^3.6.0",
     "espree": "^3.4.0",
     "esquery": "^1.0.0",
     "estraverse": "^4.2.0",
@@ -71,42 +71,42 @@
     "user-home": "^2.0.0"
   },
   "devDependencies": {
-    "babel-polyfill": "^6.9.1",
-    "babel-preset-es2015": "^6.9.0",
+    "babel-polyfill": "^6.23.0",
+    "babel-preset-es2015": "^6.24.0",
     "babelify": "^7.3.0",
-    "beefy": "^2.0.0",
-    "brfs": "0.0.9",
-    "browserify": "^12.0.1",
+    "beefy": "^2.1.8",
+    "brfs": "1.4.3",
+    "browserify": "^14.1.0",
     "chai": "^3.5.0",
-    "cheerio": "^0.19.0",
-    "coveralls": "^2.11.16",
-    "dateformat": "^1.0.8",
-    "ejs": "^2.3.3",
+    "cheerio": "^0.22.0",
+    "coveralls": "^2.12.0",
+    "dateformat": "^2.0.0",
+    "ejs": "^2.5.6",
     "eslint-plugin-eslint-plugin": "^0.7.1",
-    "eslint-plugin-node": "^4.1.0",
-    "eslint-release": "^0.10.0",
-    "esprima": "^2.4.1",
+    "eslint-plugin-node": "^4.2.1",
+    "eslint-release": "^0.10.1",
+    "esprima": "^3.1.3",
     "esprima-fb": "^15001.1001.0-dev-harmony-fb",
-    "istanbul": "^0.4.0",
-    "jsdoc": "^3.3.0-beta1",
-    "karma": "^0.13.22",
+    "istanbul": "^0.4.5",
+    "jsdoc": "^3.4.3",
+    "karma": "^1.5.0",
     "karma-babel-preprocessor": "^6.0.1",
-    "karma-mocha": "^1.0.1",
-    "karma-mocha-reporter": "^2.0.3",
-    "karma-phantomjs-launcher": "^1.0.0",
-    "leche": "^2.1.1",
+    "karma-mocha": "^1.3.0",
+    "karma-mocha-reporter": "^2.2.2",
+    "karma-phantomjs-launcher": "^1.0.4",
+    "leche": "^2.1.2",
     "load-perf": "^0.2.0",
-    "markdownlint": "^0.3.1",
-    "mocha": "^2.4.5",
+    "markdownlint": "^0.4.0",
+    "mocha": "^3.2.0",
     "mock-fs": "^4.2.0",
-    "npm-license": "^0.3.2",
-    "phantomjs-prebuilt": "^2.1.7",
-    "proxyquire": "^1.7.10",
-    "semver": "^5.0.3",
-    "shelljs-nodecli": "~0.1.0",
-    "sinon": "^1.17.2",
+    "npm-license": "^0.3.3",
+    "phantomjs-prebuilt": "^2.1.14",
+    "proxyquire": "^1.7.11",
+    "semver": "^5.3.0",
+    "shelljs-nodecli": "~0.1.1",
+    "sinon": "^2.0.0",
     "temp": "^0.8.3",
-    "through": "^2.3.6"
+    "through": "^2.3.8"
   },
   "keywords": [
     "ast",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 6f47d7d87..815a82bdd 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -34,6 +34,7 @@ rules:
         beforeLineComment: true,
         afterLineComment: false
     }]
+    max-statements-per-line: "error"
     new-cap: "error"
     newline-after-var: "error"
     new-parens: "error"


Test patch:
diff --git a/tests/fixtures/config-rule/schemas.js b/tests/fixtures/config-rule/schemas.js
index 7eb77fdae..d74bcce1d 100644
--- a/tests/fixtures/config-rule/schemas.js
+++ b/tests/fixtures/config-rule/schemas.js
@@ -69,6 +69,22 @@ module.exports = {
         "additionalProperties": false
     }],
 
+    mixedObjectWithNothingEnum: [{
+        "type": "object",
+        "properties": {},
+        "additionalProperties": false
+    },
+    {
+        "enum": ["always", "never"]
+    }],
+
+    mixedStringEnum: [{
+        "type": "string"
+    },
+    {
+        "enum": ["always", "never"]
+    }],
+
     oneOf: [{
         "oneOf": [
             {
diff --git a/tests/fixtures/parsers/babel-eslint5/destructuring-object-spread.js b/tests/fixtures/parsers/babel-eslint5/destructuring-object-spread.js
new file mode 100644
index 000000000..985446c22
--- /dev/null
+++ b/tests/fixtures/parsers/babel-eslint5/destructuring-object-spread.js
@@ -0,0 +1,1726 @@
+"use strict";
+
+// The AST from babel-eslint version 5.x, for the following code:
+//
+//     let { name, ...otherStuff } = obj; otherStuff = {};
+//
+
+exports.parse = function() {
+    return {
+        type: "Program",
+        start: 0,
+        end: 53,
+        loc: {
+            start: {
+                line: 1,
+                column: 0
+            },
+            end: {
+                line: 3,
+                column: 0
+            }
+        },
+        sourceType: "module",
+        body: [
+            {
+                type: "VariableDeclaration",
+                start: 0,
+                end: 34,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 0
+                    },
+                    end: {
+                        line: 1,
+                        column: 34
+                    }
+                },
+                declarations: [
+                    {
+                        type: "VariableDeclarator",
+                        start: 4,
+                        end: 33,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 4
+                            },
+                            end: {
+                                line: 1,
+                                column: 33
+                            }
+                        },
+                        id: {
+                            type: "ObjectPattern",
+                            start: 4,
+                            end: 27,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 4
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 27
+                                }
+                            },
+                            properties: [
+                                {
+                                    type: "Property",
+                                    start: 6,
+                                    end: 10,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 6
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 10
+                                        }
+                                    },
+                                    method: false,
+                                    shorthand: true,
+                                    computed: false,
+                                    key: {
+                                        type: "Identifier",
+                                        start: 6,
+                                        end: 10,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 6
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 10
+                                            }
+                                        },
+                                        name: "name",
+                                        range: [
+                                            6,
+                                            10
+                                        ],
+                                        _babelType: "Identifier"
+                                    },
+                                    kind: "init",
+                                    value: {
+                                        type: "Identifier",
+                                        start: 6,
+                                        end: 10,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 6
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 10
+                                            }
+                                        },
+                                        name: "name",
+                                        range: [
+                                            6,
+                                            10
+                                        ],
+                                        _babelType: "Identifier"
+                                    },
+                                    range: [
+                                        6,
+                                        10
+                                    ],
+                                    _babelType: "Property"
+                                },
+                                {
+                                    type: "SpreadProperty",
+                                    start: 12,
+                                    end: 25,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 12
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 25
+                                        }
+                                    },
+                                    argument: {
+                                        type: "Identifier",
+                                        start: 15,
+                                        end: 25,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 15
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 25
+                                            }
+                                        },
+                                        name: "otherStuff",
+                                        range: [
+                                            15,
+                                            25
+                                        ],
+                                        _babelType: "Identifier"
+                                    },
+                                    range: [
+                                        12,
+                                        25
+                                    ],
+                                    _babelType: "SpreadProperty",
+                                    value: {
+                                        type: "Identifier",
+                                        start: 15,
+                                        end: 25,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 15
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 25
+                                            }
+                                        },
+                                        name: "otherStuff",
+                                        range: [
+                                            15,
+                                            25
+                                        ],
+                                        _babelType: "Identifier"
+                                    },
+                                    key: {
+                                        type: "Identifier",
+                                        start: 15,
+                                        end: 25,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 15
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 25
+                                            }
+                                        },
+                                        name: "otherStuff",
+                                        range: [
+                                            15,
+                                            25
+                                        ],
+                                        _babelType: "Identifier"
+                                    }
+                                }
+                            ],
+                            range: [
+                                4,
+                                27
+                            ],
+                            _babelType: "ObjectPattern"
+                        },
+                        init: {
+                            type: "Identifier",
+                            start: 30,
+                            end: 33,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 30
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 33
+                                }
+                            },
+                            name: "obj",
+                            range: [
+                                30,
+                                33
+                            ],
+                            _babelType: "Identifier"
+                        },
+                        range: [
+                            4,
+                            33
+                        ],
+                        _babelType: "VariableDeclarator"
+                    }
+                ],
+                kind: "let",
+                range: [
+                    0,
+                    34
+                ],
+                _babelType: "VariableDeclaration"
+            },
+            {
+                type: "ExpressionStatement",
+                start: 35,
+                end: 51,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 35
+                    },
+                    end: {
+                        line: 1,
+                        column: 51
+                    }
+                },
+                expression: {
+                    type: "AssignmentExpression",
+                    start: 35,
+                    end: 50,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 35
+                        },
+                        end: {
+                            line: 1,
+                            column: 50
+                        }
+                    },
+                    operator: "=",
+                    left: {
+                        type: "Identifier",
+                        start: 35,
+                        end: 45,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 35
+                            },
+                            end: {
+                                line: 1,
+                                column: 45
+                            }
+                        },
+                        name: "otherStuff",
+                        range: [
+                            35,
+                            45
+                        ],
+                        _babelType: "Identifier"
+                    },
+                    right: {
+                        type: "ObjectExpression",
+                        start: 48,
+                        end: 50,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 48
+                            },
+                            end: {
+                                line: 1,
+                                column: 50
+                            }
+                        },
+                        properties: [],
+                        range: [
+                            48,
+                            50
+                        ],
+                        _babelType: "ObjectExpression"
+                    },
+                    range: [
+                        35,
+                        50
+                    ],
+                    _babelType: "AssignmentExpression"
+                },
+                range: [
+                    35,
+                    51
+                ],
+                _babelType: "ExpressionStatement"
+            }
+        ],
+        tokens: [
+            {
+                type: "Keyword",
+                value: "let",
+                start: 0,
+                end: 3,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 0
+                    },
+                    end: {
+                        line: 1,
+                        column: 3
+                    }
+                },
+                range: [
+                    0,
+                    3
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "{",
+                start: 4,
+                end: 5,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 4
+                    },
+                    end: {
+                        line: 1,
+                        column: 5
+                    }
+                },
+                range: [
+                    4,
+                    5
+                ]
+            },
+            {
+                type: "Identifier",
+                value: "name",
+                start: 6,
+                end: 10,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 6
+                    },
+                    end: {
+                        line: 1,
+                        column: 10
+                    }
+                },
+                range: [
+                    6,
+                    10
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: ",",
+                start: 10,
+                end: 11,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 10
+                    },
+                    end: {
+                        line: 1,
+                        column: 11
+                    }
+                },
+                range: [
+                    10,
+                    11
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "...",
+                start: 12,
+                end: 15,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 12
+                    },
+                    end: {
+                        line: 1,
+                        column: 15
+                    }
+                },
+                range: [
+                    12,
+                    15
+                ]
+            },
+            {
+                type: "Identifier",
+                value: "otherStuff",
+                start: 15,
+                end: 25,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 15
+                    },
+                    end: {
+                        line: 1,
+                        column: 25
+                    }
+                },
+                range: [
+                    15,
+                    25
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "}",
+                start: 26,
+                end: 27,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 26
+                    },
+                    end: {
+                        line: 1,
+                        column: 27
+                    }
+                },
+                range: [
+                    26,
+                    27
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "=",
+                start: 28,
+                end: 29,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 28
+                    },
+                    end: {
+                        line: 1,
+                        column: 29
+                    }
+                },
+                range: [
+                    28,
+                    29
+                ]
+            },
+            {
+                type: "Identifier",
+                value: "obj",
+                start: 30,
+                end: 33,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 30
+                    },
+                    end: {
+                        line: 1,
+                        column: 33
+                    }
+                },
+                range: [
+                    30,
+                    33
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: ";",
+                start: 33,
+                end: 34,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 33
+                    },
+                    end: {
+                        line: 1,
+                        column: 34
+                    }
+                },
+                range: [
+                    33,
+                    34
+                ]
+            },
+            {
+                type: "Identifier",
+                value: "otherStuff",
+                start: 35,
+                end: 45,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 35
+                    },
+                    end: {
+                        line: 1,
+                        column: 45
+                    }
+                },
+                range: [
+                    35,
+                    45
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "=",
+                start: 46,
+                end: 47,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 46
+                    },
+                    end: {
+                        line: 1,
+                        column: 47
+                    }
+                },
+                range: [
+                    46,
+                    47
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "{",
+                start: 48,
+                end: 49,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 48
+                    },
+                    end: {
+                        line: 1,
+                        column: 49
+                    }
+                },
+                range: [
+                    48,
+                    49
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: "}",
+                start: 49,
+                end: 50,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 49
+                    },
+                    end: {
+                        line: 1,
+                        column: 50
+                    }
+                },
+                range: [
+                    49,
+                    50
+                ]
+            },
+            {
+                type: "Punctuator",
+                value: ";",
+                start: 50,
+                end: 51,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 50
+                    },
+                    end: {
+                        line: 1,
+                        column: 51
+                    }
+                },
+                range: [
+                    50,
+                    51
+                ]
+            },
+            {
+                type: {
+                    label: "eof",
+                    beforeExpr: false,
+                    startsExpr: false,
+                    rightAssociative: false,
+                    isLoop: false,
+                    isAssign: false,
+                    prefix: false,
+                    postfix: false,
+                    binop: null,
+                    updateContext: null
+                },
+                start: 53,
+                end: 53,
+                loc: {
+                    start: {
+                        line: 3,
+                        column: 0
+                    },
+                    end: {
+                        line: 3,
+                        column: 0
+                    }
+                },
+                range: [
+                    53,
+                    53
+                ]
+            }
+        ],
+        comments: [],
+        range: [
+            0,
+            53
+        ],
+        _paths: [
+            {
+                contexts: [],
+                parent: "[Circular ~]",
+                data: {},
+                shouldSkip: false,
+                shouldStop: false,
+                removed: false,
+                opts: {
+                    noScope: true,
+                    enter: [
+                        null
+                    ],
+                    exit: [
+                        null
+                    ],
+                    _exploded: true,
+                    _verified: true
+                },
+                skipKeys: {},
+                parentPath: null,
+                context: {
+                    queue: null,
+                    opts: {
+                        noScope: true,
+                        enter: [
+                            null
+                        ],
+                        exit: [
+                            null
+                        ],
+                        _exploded: true,
+                        _verified: true
+                    }
+                },
+                container: [
+                    {
+                        type: "VariableDeclaration",
+                        start: 0,
+                        end: 34,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 0
+                            },
+                            end: {
+                                line: 1,
+                                column: 34
+                            }
+                        },
+                        declarations: [
+                            {
+                                type: "VariableDeclarator",
+                                start: 4,
+                                end: 33,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 4
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 33
+                                    }
+                                },
+                                id: {
+                                    type: "ObjectPattern",
+                                    start: 4,
+                                    end: 27,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 4
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 27
+                                        }
+                                    },
+                                    properties: [
+                                        {
+                                            type: "Property",
+                                            start: 6,
+                                            end: 10,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 6
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 10
+                                                }
+                                            },
+                                            method: false,
+                                            shorthand: true,
+                                            computed: false,
+                                            key: {
+                                                type: "Identifier",
+                                                start: 6,
+                                                end: 10,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 6
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 10
+                                                    }
+                                                },
+                                                name: "name",
+                                                range: [
+                                                    6,
+                                                    10
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            kind: "init",
+                                            value: {
+                                                type: "Identifier",
+                                                start: 6,
+                                                end: 10,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 6
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 10
+                                                    }
+                                                },
+                                                name: "name",
+                                                range: [
+                                                    6,
+                                                    10
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            range: [
+                                                6,
+                                                10
+                                            ],
+                                            _babelType: "Property"
+                                        },
+                                        {
+                                            type: "SpreadProperty",
+                                            start: 12,
+                                            end: 25,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 12
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 25
+                                                }
+                                            },
+                                            argument: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            range: [
+                                                12,
+                                                25
+                                            ],
+                                            _babelType: "SpreadProperty",
+                                            value: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            key: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            }
+                                        }
+                                    ],
+                                    range: [
+                                        4,
+                                        27
+                                    ],
+                                    _babelType: "ObjectPattern"
+                                },
+                                init: {
+                                    type: "Identifier",
+                                    start: 30,
+                                    end: 33,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 30
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 33
+                                        }
+                                    },
+                                    name: "obj",
+                                    range: [
+                                        30,
+                                        33
+                                    ],
+                                    _babelType: "Identifier"
+                                },
+                                range: [
+                                    4,
+                                    33
+                                ],
+                                _babelType: "VariableDeclarator"
+                            }
+                        ],
+                        kind: "let",
+                        range: [
+                            0,
+                            34
+                        ],
+                        _babelType: "VariableDeclaration"
+                    },
+                    {
+                        type: "ExpressionStatement",
+                        start: 35,
+                        end: 51,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 35
+                            },
+                            end: {
+                                line: 1,
+                                column: 51
+                            }
+                        },
+                        expression: {
+                            type: "AssignmentExpression",
+                            start: 35,
+                            end: 50,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 35
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 50
+                                }
+                            },
+                            operator: "=",
+                            left: {
+                                type: "Identifier",
+                                start: 35,
+                                end: 45,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 35
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 45
+                                    }
+                                },
+                                name: "otherStuff",
+                                range: [
+                                    35,
+                                    45
+                                ],
+                                _babelType: "Identifier"
+                            },
+                            right: {
+                                type: "ObjectExpression",
+                                start: 48,
+                                end: 50,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 48
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 50
+                                    }
+                                },
+                                properties: [],
+                                range: [
+                                    48,
+                                    50
+                                ],
+                                _babelType: "ObjectExpression"
+                            },
+                            range: [
+                                35,
+                                50
+                            ],
+                            _babelType: "AssignmentExpression"
+                        },
+                        range: [
+                            35,
+                            51
+                        ],
+                        _babelType: "ExpressionStatement"
+                    }
+                ],
+                listKey: "body",
+                inList: true,
+                parentKey: "body",
+                key: 0,
+                node: {
+                    type: "VariableDeclaration",
+                    start: 0,
+                    end: 34,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 0
+                        },
+                        end: {
+                            line: 1,
+                            column: 34
+                        }
+                    },
+                    declarations: [
+                        {
+                            type: "VariableDeclarator",
+                            start: 4,
+                            end: 33,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 4
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 33
+                                }
+                            },
+                            id: {
+                                type: "ObjectPattern",
+                                start: 4,
+                                end: 27,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 4
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 27
+                                    }
+                                },
+                                properties: [
+                                    {
+                                        type: "Property",
+                                        start: 6,
+                                        end: 10,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 6
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 10
+                                            }
+                                        },
+                                        method: false,
+                                        shorthand: true,
+                                        computed: false,
+                                        key: {
+                                            type: "Identifier",
+                                            start: 6,
+                                            end: 10,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 6
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 10
+                                                }
+                                            },
+                                            name: "name",
+                                            range: [
+                                                6,
+                                                10
+                                            ],
+                                            _babelType: "Identifier"
+                                        },
+                                        kind: "init",
+                                        value: {
+                                            type: "Identifier",
+                                            start: 6,
+                                            end: 10,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 6
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 10
+                                                }
+                                            },
+                                            name: "name",
+                                            range: [
+                                                6,
+                                                10
+                                            ],
+                                            _babelType: "Identifier"
+                                        },
+                                        range: [
+                                            6,
+                                            10
+                                        ],
+                                        _babelType: "Property"
+                                    },
+                                    {
+                                        type: "SpreadProperty",
+                                        start: 12,
+                                        end: 25,
+                                        loc: {
+                                            start: {
+                                                line: 1,
+                                                column: 12
+                                            },
+                                            end: {
+                                                line: 1,
+                                                column: 25
+                                            }
+                                        },
+                                        argument: {
+                                            type: "Identifier",
+                                            start: 15,
+                                            end: 25,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 15
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 25
+                                                }
+                                            },
+                                            name: "otherStuff",
+                                            range: [
+                                                15,
+                                                25
+                                            ],
+                                            _babelType: "Identifier"
+                                        },
+                                        range: [
+                                            12,
+                                            25
+                                        ],
+                                        _babelType: "SpreadProperty",
+                                        value: {
+                                            type: "Identifier",
+                                            start: 15,
+                                            end: 25,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 15
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 25
+                                                }
+                                            },
+                                            name: "otherStuff",
+                                            range: [
+                                                15,
+                                                25
+                                            ],
+                                            _babelType: "Identifier"
+                                        },
+                                        key: {
+                                            type: "Identifier",
+                                            start: 15,
+                                            end: 25,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 15
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 25
+                                                }
+                                            },
+                                            name: "otherStuff",
+                                            range: [
+                                                15,
+                                                25
+                                            ],
+                                            _babelType: "Identifier"
+                                        }
+                                    }
+                                ],
+                                range: [
+                                    4,
+                                    27
+                                ],
+                                _babelType: "ObjectPattern"
+                            },
+                            init: {
+                                type: "Identifier",
+                                start: 30,
+                                end: 33,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 30
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 33
+                                    }
+                                },
+                                name: "obj",
+                                range: [
+                                    30,
+                                    33
+                                ],
+                                _babelType: "Identifier"
+                            },
+                            range: [
+                                4,
+                                33
+                            ],
+                            _babelType: "VariableDeclarator"
+                        }
+                    ],
+                    kind: "let",
+                    range: [
+                        0,
+                        34
+                    ],
+                    _babelType: "VariableDeclaration"
+                },
+                scope: null,
+                type: "VariableDeclaration",
+                typeAnnotation: null
+            },
+            {
+                contexts: [],
+                parent: "[Circular ~]",
+                data: {},
+                shouldSkip: false,
+                shouldStop: false,
+                removed: false,
+                opts: {
+                    noScope: true,
+                    enter: [
+                        null
+                    ],
+                    exit: [
+                        null
+                    ],
+                    _exploded: true,
+                    _verified: true
+                },
+                skipKeys: {},
+                parentPath: null,
+                context: {
+                    queue: null,
+                    opts: {
+                        noScope: true,
+                        enter: [
+                            null
+                        ],
+                        exit: [
+                            null
+                        ],
+                        _exploded: true,
+                        _verified: true
+                    }
+                },
+                container: [
+                    {
+                        type: "VariableDeclaration",
+                        start: 0,
+                        end: 34,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 0
+                            },
+                            end: {
+                                line: 1,
+                                column: 34
+                            }
+                        },
+                        declarations: [
+                            {
+                                type: "VariableDeclarator",
+                                start: 4,
+                                end: 33,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 4
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 33
+                                    }
+                                },
+                                id: {
+                                    type: "ObjectPattern",
+                                    start: 4,
+                                    end: 27,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 4
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 27
+                                        }
+                                    },
+                                    properties: [
+                                        {
+                                            type: "Property",
+                                            start: 6,
+                                            end: 10,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 6
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 10
+                                                }
+                                            },
+                                            method: false,
+                                            shorthand: true,
+                                            computed: false,
+                                            key: {
+                                                type: "Identifier",
+                                                start: 6,
+                                                end: 10,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 6
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 10
+                                                    }
+                                                },
+                                                name: "name",
+                                                range: [
+                                                    6,
+                                                    10
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            kind: "init",
+                                            value: {
+                                                type: "Identifier",
+                                                start: 6,
+                                                end: 10,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 6
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 10
+                                                    }
+                                                },
+                                                name: "name",
+                                                range: [
+                                                    6,
+                                                    10
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            range: [
+                                                6,
+                                                10
+                                            ],
+                                            _babelType: "Property"
+                                        },
+                                        {
+                                            type: "SpreadProperty",
+                                            start: 12,
+                                            end: 25,
+                                            loc: {
+                                                start: {
+                                                    line: 1,
+                                                    column: 12
+                                                },
+                                                end: {
+                                                    line: 1,
+                                                    column: 25
+                                                }
+                                            },
+                                            argument: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            range: [
+                                                12,
+                                                25
+                                            ],
+                                            _babelType: "SpreadProperty",
+                                            value: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            },
+                                            key: {
+                                                type: "Identifier",
+                                                start: 15,
+                                                end: 25,
+                                                loc: {
+                                                    start: {
+                                                        line: 1,
+                                                        column: 15
+                                                    },
+                                                    end: {
+                                                        line: 1,
+                                                        column: 25
+                                                    }
+                                                },
+                                                name: "otherStuff",
+                                                range: [
+                                                    15,
+                                                    25
+                                                ],
+                                                _babelType: "Identifier"
+                                            }
+                                        }
+                                    ],
+                                    range: [
+                                        4,
+                                        27
+                                    ],
+                                    _babelType: "ObjectPattern"
+                                },
+                                init: {
+                                    type: "Identifier",
+                                    start: 30,
+                                    end: 33,
+                                    loc: {
+                                        start: {
+                                            line: 1,
+                                            column: 30
+                                        },
+                                        end: {
+                                            line: 1,
+                                            column: 33
+                                        }
+                                    },
+                                    name: "obj",
+                                    range: [
+                                        30,
+                                        33
+                                    ],
+                                    _babelType: "Identifier"
+                                },
+                                range: [
+                                    4,
+                                    33
+                                ],
+                                _babelType: "VariableDeclarator"
+                            }
+                        ],
+                        kind: "let",
+                        range: [
+                            0,
+                            34
+                        ],
+                        _babelType: "VariableDeclaration"
+                    },
+                    {
+                        type: "ExpressionStatement",
+                        start: 35,
+                        end: 51,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 35
+                            },
+                            end: {
+                                line: 1,
+                                column: 51
+                            }
+                        },
+                        expression: {
+                            type: "AssignmentExpression",
+                            start: 35,
+                            end: 50,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 35
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 50
+                                }
+                            },
+                            operator: "=",
+                            left: {
+                                type: "Identifier",
+                                start: 35,
+                                end: 45,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 35
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 45
+                                    }
+                                },
+                                name: "otherStuff",
+                                range: [
+                                    35,
+                                    45
+                                ],
+                                _babelType: "Identifier"
+                            },
+                            right: {
+                                type: "ObjectExpression",
+                                start: 48,
+                                end: 50,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 48
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 50
+                                    }
+                                },
+                                properties: [],
+                                range: [
+                                    48,
+                                    50
+                                ],
+                                _babelType: "ObjectExpression"
+                            },
+                            range: [
+                                35,
+                                50
+                            ],
+                            _babelType: "AssignmentExpression"
+                        },
+                        range: [
+                            35,
+                            51
+                        ],
+                        _babelType: "ExpressionStatement"
+                    }
+                ],
+                listKey: "body",
+                inList: true,
+                parentKey: "body",
+                key: 1,
+                node: {
+                    type: "ExpressionStatement",
+                    start: 35,
+                    end: 51,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 35
+                        },
+                        end: {
+                            line: 1,
+                            column: 51
+                        }
+                    },
+                    expression: {
+                        type: "AssignmentExpression",
+                        start: 35,
+                        end: 50,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 35
+                            },
+                            end: {
+                                line: 1,
+                                column: 50
+                            }
+                        },
+                        operator: "=",
+                        left: {
+                            type: "Identifier",
+                            start: 35,
+                            end: 45,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 35
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 45
+                                }
+                            },
+                            name: "otherStuff",
+                            range: [
+                                35,
+                                45
+                            ],
+                            _babelType: "Identifier"
+                        },
+                        right: {
+                            type: "ObjectExpression",
+                            start: 48,
+                            end: 50,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 48
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 50
+                                }
+                            },
+                            properties: [],
+                            range: [
+                                48,
+                                50
+                            ],
+                            _babelType: "ObjectExpression"
+                        },
+                        range: [
+                            35,
+                            50
+                        ],
+                        _babelType: "AssignmentExpression"
+                    },
+                    range: [
+                        35,
+                        51
+                    ],
+                    _babelType: "ExpressionStatement"
+                },
+                scope: null,
+                type: "ExpressionStatement",
+                typeAnnotation: null
+            }
+        ]
+    };
+};
diff --git a/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js b/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js
new file mode 100644
index 000000000..a663b4e1e
--- /dev/null
+++ b/tests/fixtures/parsers/babel-eslint7/function-type-annotation.js
@@ -0,0 +1,525 @@
+"use strict";
+
+/**
+ * Parser: babel-eslint v7.2.1
+ * Source code:
+ * type TransformFunction = (el: ASTElement, code: string) => string;
+ */
+
+exports.parse = () => ({
+    type: "Program",
+    start: 0,
+    end: 66,
+    loc: {
+        start: {
+            line: 1,
+            column: 0
+        },
+        end: {
+            line: 1,
+            column: 66
+        }
+    },
+    comments: [],
+    tokens: [
+        {
+            type: "Identifier",
+            value: "type",
+            start: 0,
+            end: 4,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 4
+                }
+            },
+            range: [
+                0,
+                4
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "TransformFunction",
+            start: 5,
+            end: 22,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 5
+                },
+                end: {
+                    line: 1,
+                    column: 22
+                }
+            },
+            range: [
+                5,
+                22
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "=",
+            start: 23,
+            end: 24,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 23
+                },
+                end: {
+                    line: 1,
+                    column: 24
+                }
+            },
+            range: [
+                23,
+                24
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "(",
+            start: 25,
+            end: 26,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 25
+                },
+                end: {
+                    line: 1,
+                    column: 26
+                }
+            },
+            range: [
+                25,
+                26
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "el",
+            start: 26,
+            end: 28,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 26
+                },
+                end: {
+                    line: 1,
+                    column: 28
+                }
+            },
+            range: [
+                26,
+                28
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ":",
+            start: 28,
+            end: 29,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 28
+                },
+                end: {
+                    line: 1,
+                    column: 29
+                }
+            },
+            range: [
+                28,
+                29
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "ASTElement",
+            start: 30,
+            end: 40,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 30
+                },
+                end: {
+                    line: 1,
+                    column: 40
+                }
+            },
+            range: [
+                30,
+                40
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ",",
+            start: 40,
+            end: 41,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 40
+                },
+                end: {
+                    line: 1,
+                    column: 41
+                }
+            },
+            range: [
+                40,
+                41
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "code",
+            start: 42,
+            end: 46,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 42
+                },
+                end: {
+                    line: 1,
+                    column: 46
+                }
+            },
+            range: [
+                42,
+                46
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ":",
+            start: 46,
+            end: 47,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 46
+                },
+                end: {
+                    line: 1,
+                    column: 47
+                }
+            },
+            range: [
+                46,
+                47
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "string",
+            start: 48,
+            end: 54,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 48
+                },
+                end: {
+                    line: 1,
+                    column: 54
+                }
+            },
+            range: [
+                48,
+                54
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ")",
+            start: 54,
+            end: 55,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 54
+                },
+                end: {
+                    line: 1,
+                    column: 55
+                }
+            },
+            range: [
+                54,
+                55
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: "=>",
+            start: 56,
+            end: 58,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 56
+                },
+                end: {
+                    line: 1,
+                    column: 58
+                }
+            },
+            range: [
+                56,
+                58
+            ]
+        },
+        {
+            type: "Identifier",
+            value: "string",
+            start: 59,
+            end: 65,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 59
+                },
+                end: {
+                    line: 1,
+                    column: 65
+                }
+            },
+            range: [
+                59,
+                65
+            ]
+        },
+        {
+            type: "Punctuator",
+            value: ";",
+            start: 65,
+            end: 66,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 65
+                },
+                end: {
+                    line: 1,
+                    column: 66
+                }
+            },
+            range: [
+                65,
+                66
+            ]
+        }
+    ],
+    range: [
+        0,
+        66
+    ],
+    sourceType: "module",
+    body: [
+        {
+            type: "TypeAlias",
+            start: 0,
+            end: 66,
+            loc: {
+                start: {
+                    line: 1,
+                    column: 0
+                },
+                end: {
+                    line: 1,
+                    column: 66
+                }
+            },
+            id: {
+                type: "Identifier",
+                start: 5,
+                end: 22,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 5
+                    },
+                    end: {
+                        line: 1,
+                        column: 22
+                    },
+                    identifierName: "TransformFunction"
+                },
+                name: "TransformFunction",
+                range: [
+                    5,
+                    22
+                ],
+                _babelType: "Identifier"
+            },
+            typeParameters: null,
+            right: {
+                type: "FunctionTypeAnnotation",
+                start: 25,
+                end: 65,
+                loc: {
+                    start: {
+                        line: 1,
+                        column: 25
+                    },
+                    end: {
+                        line: 1,
+                        column: 65
+                    }
+                },
+                params: [
+                    {
+                        type: "FunctionTypeParam",
+                        start: 26,
+                        end: 40,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 26
+                            },
+                            end: {
+                                line: 1,
+                                column: 40
+                            }
+                        },
+                        optional: false,
+                        typeAnnotation: {
+                            type: "GenericTypeAnnotation",
+                            start: 30,
+                            end: 40,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 30
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 40
+                                }
+                            },
+                            typeParameters: null,
+                            id: {
+                                type: "Identifier",
+                                start: 30,
+                                end: 40,
+                                loc: {
+                                    start: {
+                                        line: 1,
+                                        column: 30
+                                    },
+                                    end: {
+                                        line: 1,
+                                        column: 40
+                                    },
+                                    identifierName: "ASTElement"
+                                },
+                                name: "ASTElement",
+                                range: [
+                                    30,
+                                    40
+                                ],
+                                _babelType: "Identifier"
+                            },
+                            range: [
+                                30,
+                                40
+                            ],
+                            _babelType: "GenericTypeAnnotation"
+                        },
+                        range: [
+                            26,
+                            40
+                        ],
+                        _babelType: "FunctionTypeParam"
+                    },
+                    {
+                        type: "FunctionTypeParam",
+                        start: 42,
+                        end: 54,
+                        loc: {
+                            start: {
+                                line: 1,
+                                column: 42
+                            },
+                            end: {
+                                line: 1,
+                                column: 54
+                            }
+                        },
+                        optional: false,
+                        typeAnnotation: {
+                            type: "StringTypeAnnotation",
+                            start: 48,
+                            end: 54,
+                            loc: {
+                                start: {
+                                    line: 1,
+                                    column: 48
+                                },
+                                end: {
+                                    line: 1,
+                                    column: 54
+                                }
+                            },
+                            range: [
+                                48,
+                                54
+                            ],
+                            _babelType: "StringTypeAnnotation"
+                        },
+                        range: [
+                            42,
+                            54
+                        ],
+                        _babelType: "FunctionTypeParam"
+                    }
+                ],
+                rest: null,
+                returnType: {
+                    type: "StringTypeAnnotation",
+                    start: 59,
+                    end: 65,
+                    loc: {
+                        start: {
+                            line: 1,
+                            column: 59
+                        },
+                        end: {
+                            line: 1,
+                            column: 65
+                        }
+                    },
+                    range: [
+                        59,
+                        65
+                    ],
+                    _babelType: "StringTypeAnnotation"
+                },
+                typeParameters: null,
+                range: [
+                    25,
+                    65
+                ],
+                _babelType: "FunctionTypeAnnotation"
+            },
+            range: [
+                0,
+                66
+            ],
+            _babelType: "TypeAlias"
+        }
+    ]
+});
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index 4e916ebb2..611c08fc0 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -71,7 +71,7 @@ describe("configInitializer", () => {
 
     beforeEach(() => {
         npmInstallStub = sinon.stub(npmUtil, "installSyncSaveDev");
-        npmCheckStub = sinon.stub(npmUtil, "checkDevDeps", packages => packages.reduce((status, pkg) => {
+        npmCheckStub = sinon.stub(npmUtil, "checkDevDeps").callsFake(packages => packages.reduce((status, pkg) => {
             status[pkg] = false;
             return status;
         }, {}));
diff --git a/tests/lib/config/config-rule.js b/tests/lib/config/config-rule.js
index a801e91c8..f41e3bfc6 100644
--- a/tests/lib/config/config-rule.js
+++ b/tests/lib/config/config-rule.js
@@ -230,7 +230,7 @@ describe("ConfigRule", () => {
             });
         });
 
-        describe("for a schema with an enum and an object with no usable properties", () => {
+        describe("for a schema with an enum followed by an object with no usable properties", () => {
             before(() => {
                 actualConfigs = ConfigRule.generateConfigsFromSchema(schema.mixedEnumObjectWithNothing);
             });
@@ -242,6 +242,30 @@ describe("ConfigRule", () => {
             });
         });
 
+        describe("for a schema with an enum preceded by an object with no usable properties", () => {
+            before(() => {
+                actualConfigs = ConfigRule.generateConfigsFromSchema(schema.mixedObjectWithNothingEnum);
+            });
+
+            it("should not create a config for the enum", () => {
+                const expectedConfigs = [2];
+
+                assert.sameDeepMembers(actualConfigs, expectedConfigs);
+            });
+        });
+
+        describe("for a schema with an enum preceded by a string", () => {
+            before(() => {
+                actualConfigs = ConfigRule.generateConfigsFromSchema(schema.mixedStringEnum);
+            });
+
+            it("should not create a config for the enum", () => {
+                const expectedConfigs = [2];
+
+                assert.sameDeepMembers(actualConfigs, expectedConfigs);
+            });
+        });
+
         describe("for a schema with oneOf", () => {
 
             before(() => {
diff --git a/tests/lib/config/plugins.js b/tests/lib/config/plugins.js
index 06b2bcd38..61b759797 100644
--- a/tests/lib/config/plugins.js
+++ b/tests/lib/config/plugins.js
@@ -43,7 +43,12 @@ describe("Plugins", () => {
                 "eslint-plugin-example": plugin,
                 "@scope/eslint-plugin-example": scopedPlugin,
                 "./environments": Environments,
-                "../rules": Rules
+                "../rules": Rules,
+                "eslint-plugin-throws-on-load": {
+                    get rules() {
+                        throw new Error("error thrown while loading this module");
+                    }
+                }
             });
         });
 
@@ -106,6 +111,21 @@ describe("Plugins", () => {
             }, /Failed to load plugin/);
         });
 
+        it("should rethrow an error that a plugin throws on load", () => {
+            try {
+                StubbedPlugins.load("throws-on-load");
+            } catch (err) {
+                assert.strictEqual(
+                    err.message,
+                    "error thrown while loading this module",
+                    "should rethrow the same error that was thrown on plugin load"
+                );
+
+                return;
+            }
+            assert.fail(null, null, "should throw an error if a plugin fails to load");
+        });
+
         it("should load a scoped plugin when referenced by short name", () => {
             StubbedPlugins.load("@scope/example");
             assert.equal(StubbedPlugins.get("@scope/example"), scopedPlugin);
diff --git a/tests/lib/eslint.js b/tests/lib/eslint.js
index 406302a69..904cb5f32 100644
--- a/tests/lib/eslint.js
+++ b/tests/lib/eslint.js
@@ -48,7 +48,7 @@ const TEST_CODE = "var answer = 6 * 7;",
 //------------------------------------------------------------------------------
 
 /**
- * Get variables in the current escope
+ * Get variables in the current scope
  * @param {Object} scope current scope
  * @param {string} name name of the variable to look for
  * @returns {ASTNode} The variable object
@@ -3425,6 +3425,16 @@ describe("eslint", () => {
 
             assert(result.length === 0);
         });
+
+
+        it("should not modify config object passed as argument", () => {
+            const config = {};
+
+            Object.freeze(config);
+            assert.doesNotThrow(() => {
+                eslint.verify("var foo", config);
+            });
+        });
     });
 
     describe("Variables and references", () => {
diff --git a/tests/lib/formatters/codeframe.js b/tests/lib/formatters/codeframe.js
index 63e45db4e..fffaea2ee 100644
--- a/tests/lib/formatters/codeframe.js
+++ b/tests/lib/formatters/codeframe.js
@@ -54,7 +54,9 @@ describe("formatter:codeframe", () => {
     describe("when passed no messages", () => {
         const code = [{
             filePath: "foo.js",
-            messages: []
+            messages: [],
+            errorCount: 0,
+            warningCount: 0
         }];
 
         it("should return nothing", () => {
@@ -64,70 +66,84 @@ describe("formatter:codeframe", () => {
         });
     });
 
-    describe("when passed a single message", () => {
+    describe("when passed a single warning message", () => {
         const code = [{
             filePath: path.join(process.cwd(), "lib", "foo.js"),
             source: "var foo = 1;\n var bar = 2;\n",
             messages: [{
                 message: "Unexpected foo.",
-                severity: 2,
+                severity: 1,
                 line: 1,
                 column: 5,
                 ruleId: "foo"
-            }]
+            }],
+            errorCount: 0,
+            warningCount: 1
         }];
 
-        it("should return a string in the correct format for errors", () => {
+        it("should return a string in the correct format for warnings", () => {
             const result = formatter(code);
 
             assert.equal(chalk.stripColor(result), [
-                `error: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
+                `warning: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
                 "> 1 | var foo = 1;",
                 "    |     ^",
                 "  2 |  var bar = 2;",
                 "  3 | ",
                 "\n",
-                "1 error found."
+                "1 warning found."
             ].join("\n"));
         });
 
-        it("should return a string in the correct format for warnings", () => {
-            code[0].messages[0].severity = 1;
+        it("should return bold yellow summary when there are only warnings", () => {
+            sandbox.spy(chalkStub.yellow, "bold");
+            sandbox.spy(chalkStub.red, "bold");
+
+            formatter(code);
+
+            assert.equal(chalkStub.yellow.bold.callCount, 1);
+            assert.equal(chalkStub.red.bold.callCount, 0);
+        });
+    });
+
+    describe("when passed a single error message", () => {
+        const code = [{
+            filePath: path.join(process.cwd(), "lib", "foo.js"),
+            source: "var foo = 1;\n var bar = 2;\n",
+            messages: [{
+                message: "Unexpected foo.",
+                severity: 2,
+                line: 1,
+                column: 5,
+                ruleId: "foo"
+            }],
+            errorCount: 1,
+            warningCount: 0
+        }];
 
+        it("should return a string in the correct format for errors", () => {
             const result = formatter(code);
 
             assert.equal(chalk.stripColor(result), [
-                `warning: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
+                `error: Unexpected foo (foo) at ${path.join("lib", "foo.js")}:1:5:`,
                 "> 1 | var foo = 1;",
                 "    |     ^",
                 "  2 |  var bar = 2;",
                 "  3 | ",
                 "\n",
-                "1 warning found."
+                "1 error found."
             ].join("\n"));
         });
 
         it("should return bold red summary when there are errors", () => {
             sandbox.spy(chalkStub.yellow, "bold");
             sandbox.spy(chalkStub.red, "bold");
-            code[0].messages[0].severity = 2;
 
             formatter(code);
 
             assert.equal(chalkStub.yellow.bold.callCount, 0);
             assert.equal(chalkStub.red.bold.callCount, 1);
         });
-
-        it("should return bold yellow summary when there are only warnings", () => {
-            sandbox.spy(chalkStub.yellow, "bold");
-            sandbox.spy(chalkStub.red, "bold");
-            code[0].messages[0].severity = 1;
-
-            formatter(code);
-
-            assert.equal(chalkStub.yellow.bold.callCount, 1);
-            assert.equal(chalkStub.red.bold.callCount, 0);
-        });
     });
 
     describe("when passed multiple messages", () => {
@@ -146,7 +162,9 @@ describe("formatter:codeframe", () => {
                 line: 1,
                 column: 7,
                 ruleId: "no-unused-vars"
-            }]
+            }],
+            errorCount: 2,
+            warningCount: 0
         }];
 
         it("should return a string with multiple entries", () => {
@@ -171,6 +189,8 @@ describe("formatter:codeframe", () => {
             sandbox.spy(chalkStub.yellow, "bold");
             sandbox.spy(chalkStub.red, "bold");
             code[0].messages[0].severity = 1;
+            code[0].warningCount = 1;
+            code[0].errorCount = 1;
 
             formatter(code);
 
@@ -190,6 +210,8 @@ describe("formatter:codeframe", () => {
                 column: 11,
                 source: "    const foo = 1;"
             }],
+            errorCount: 1,
+            warningCount: 0,
             output: "function foo() {\n\n    // a comment\n    const foo = 1;\n}\n\n"
         }];
 
@@ -221,7 +243,9 @@ describe("formatter:codeframe", () => {
                 line: 1,
                 column: 14,
                 ruleId: "semi"
-            }]
+            }],
+            errorCount: 1,
+            warningCount: 0
         }, {
             filePath: "bar.js",
             source: "const bar = 2\n",
@@ -231,7 +255,9 @@ describe("formatter:codeframe", () => {
                 line: 1,
                 column: 14,
                 ruleId: "semi"
-            }]
+            }],
+            errorCount: 1,
+            warningCount: 0
         }];
 
         it("should return a string with multiple entries", () => {
@@ -265,7 +291,9 @@ describe("formatter:codeframe", () => {
                 message: "Parsing error: Unexpected token {",
                 line: 1,
                 column: 2
-            }]
+            }],
+            errorCount: 1,
+            warningCount: 0
         }];
 
         it("should return a string in the correct format", () => {
@@ -288,7 +316,9 @@ describe("formatter:codeframe", () => {
             messages: [{
                 fatal: true,
                 message: "Couldn't find foo.js."
-            }]
+            }],
+            errorCount: 1,
+            warningCount: 0
         }];
 
         it("should return a string without code preview (codeframe)", () => {
@@ -306,7 +336,9 @@ describe("formatter:codeframe", () => {
                 message: "Unexpected foo.",
                 severity: 2,
                 source: "foo"
-            }]
+            }],
+            errorCount: 1,
+            warningCount: 0
         }];
 
         it("should return a string without code preview (codeframe)", () => {
diff --git a/tests/lib/rules/array-bracket-spacing.js b/tests/lib/rules/array-bracket-spacing.js
index bea84ff76..35f13def7 100644
--- a/tests/lib/rules/array-bracket-spacing.js
+++ b/tests/lib/rules/array-bracket-spacing.js
@@ -695,7 +695,7 @@ ruleTester.run("array-bracket-spacing", rule, {
             code: "([ a, b ]: Array<any>) => {}",
             output: "([a, b]: Array<any>) => {}",
             options: ["never"],
-            ecmaFeatures: {
+            parserOptions: {
                 ecmaVersion: 6
             },
             errors: [
@@ -718,7 +718,7 @@ ruleTester.run("array-bracket-spacing", rule, {
             code: "([a, b]: Array< any >) => {}",
             output: "([ a, b ]: Array< any >) => {}",
             options: ["always"],
-            ecmaFeatures: {
+            parserOptions: {
                 ecmaVersion: 6
             },
             errors: [
diff --git a/tests/lib/rules/comma-style.js b/tests/lib/rules/comma-style.js
index 8dcbbc883..98c765c6b 100644
--- a/tests/lib/rules/comma-style.js
+++ b/tests/lib/rules/comma-style.js
@@ -569,6 +569,11 @@ ruleTester.run("comma-style", rule, {
                 message: BAD_LN_BRK_MSG,
                 type: "Identifier"
             }]
+        },
+        {
+            code: "[(foo),\n,\nbar]",
+            output: "[(foo),,\nbar]",
+            errors: [{ message: BAD_LN_BRK_MSG }]
         }
     ]
 });
diff --git a/tests/lib/rules/dot-notation.js b/tests/lib/rules/dot-notation.js
index 83b212efd..0c28c4393 100644
--- a/tests/lib/rules/dot-notation.js
+++ b/tests/lib/rules/dot-notation.js
@@ -153,6 +153,26 @@ ruleTester.run("dot-notation", rule, {
             options: [{ allowKeywords: false }],
             errors: [{ message: ".while is a syntax error." }],
             output: null // Not fixed due to comment
+        },
+        {
+            code: "foo[('bar')]",
+            output: "foo.bar",
+            errors: [{ message: "[\"bar\"] is better written in dot notation." }]
+        },
+        {
+            code: "foo[(null)]",
+            output: "foo.null",
+            errors: [{ message: "[null] is better written in dot notation." }]
+        },
+        {
+            code: "(foo)['bar']",
+            output: "(foo).bar",
+            errors: [{ message: "[\"bar\"] is better written in dot notation." }]
+        },
+        {
+            code: "1['toString']",
+            output: "1 .toString",
+            errors: [{ message: "[\"toString\"] is better written in dot notation." }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-else-return.js b/tests/lib/rules/no-else-return.js
index e99b83d6c..6aea5c867 100644
--- a/tests/lib/rules/no-else-return.js
+++ b/tests/lib/rules/no-else-return.js
@@ -27,7 +27,22 @@ ruleTester.run("no-else-return", rule, {
         "function foo() { if (true) notAReturn(); else return y; }",
         "function foo() {if (x) { notAReturn(); } else if (y) { return true; } else { notAReturn(); } }",
         "function foo() {if (x) { return true; } else if (y) { notAReturn() } else { notAReturn(); } }",
-        "if (0) { if (0) {} else {} } else {}"
+        "if (0) { if (0) {} else {} } else {}",
+        `
+            function foo() {
+                if (foo)
+                    if (bar) return;
+                    else baz;
+                else qux;
+            }
+        `,
+        `
+            function foo() {
+                while (foo)
+                    if (bar) return;
+                    else baz;
+            }
+        `
     ],
     invalid: [
         {
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 349c14994..f554d88b5 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -410,6 +410,43 @@ ruleTester.run("no-extra-parens", rule, {
         {
             code: "const A = class extends (B=C) {}",
             parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "() => ({ foo: 1 })",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "() => ({ foo: 1 }).foo",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "() => ({ foo: 1 }.foo().bar).baz.qux()",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "() => ({ foo: 1 }.foo().bar + baz)",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "export default (function(){}).foo",
+            parserOptions: { ecmaVersion: 2015, sourceType: "module" }
+        },
+        {
+            code: "export default (class{}).foo",
+            parserOptions: { ecmaVersion: 2015, sourceType: "module" }
+        },
+        "({}).hasOwnProperty.call(foo, bar)",
+        "({}) ? foo() : bar()",
+        "({}) + foo",
+        "(function(){}) + foo",
+        "(let[foo]) = 1", // setting the 'foo' property of the 'let' variable to 1
+        {
+            code: "((function(){}).foo.bar)();",
+            options: ["functions"]
+        },
+        {
+            code: "((function(){}).foo)();",
+            options: ["functions"]
         }
     ],
 
@@ -529,8 +566,6 @@ ruleTester.run("no-extra-parens", rule, {
         invalid("bar((function(){}).foo(), 0);", "bar(function(){}.foo(), 0);", "FunctionExpression"),
         invalid("bar[(function(){}).foo()];", "bar[function(){}.foo()];", "FunctionExpression"),
         invalid("var bar = (function(){}).foo();", "var bar = function(){}.foo();", "FunctionExpression"),
-        invalid("((function(){}).foo.bar)();", "(function(){}.foo.bar)();", "FunctionExpression", null, { options: ["functions"] }),
-        invalid("((function(){}).foo)();", "(function(){}.foo)();", "FunctionExpression", null, { options: ["functions"] }),
 
         invalid("((class{})).foo();", "(class{}).foo();", "ClassExpression", null, { parserOptions: { ecmaVersion: 6 } }),
         invalid("((class{}).foo());", "(class{}).foo();", "CallExpression", null, { parserOptions: { ecmaVersion: 6 } }),
@@ -952,6 +987,20 @@ ruleTester.run("no-extra-parens", rule, {
             "AssignmentExpression",
             1,
             { parserOptions: { ecmaVersion: 2015 } }
+        ),
+        invalid(
+            "for (foo of(bar));",
+            "for (foo of bar);",
+            "Identifier",
+            1,
+            { parserOptions: { ecmaVersion: 2015 } }
+        ),
+        invalid(
+            "() => (({ foo: 1 }).foo)",
+            "() => ({ foo: 1 }).foo",
+            "MemberExpression",
+            1,
+            { parserOptions: { ecmaVersion: 2015 } }
         )
     ]
 });
diff --git a/tests/lib/rules/no-implicit-coercion.js b/tests/lib/rules/no-implicit-coercion.js
index 3b1f8e89c..5ea5f5fa4 100644
--- a/tests/lib/rules/no-implicit-coercion.js
+++ b/tests/lib/rules/no-implicit-coercion.js
@@ -221,6 +221,16 @@ ruleTester.run("no-implicit-coercion", rule, {
             parserOptions: { ecmaVersion: 6 },
             errors: [{ message: "use `String(foo)` instead.", type: "BinaryExpression" }],
             output: "var a = String(foo)"
+        },
+        {
+            code: "typeof+foo",
+            output: "typeof Number(foo)",
+            errors: [{ message: "use `Number(foo)` instead.", type: "UnaryExpression" }]
+        },
+        {
+            code: "typeof +foo",
+            output: "typeof Number(foo)",
+            errors: [{ message: "use `Number(foo)` instead.", type: "UnaryExpression" }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-param-reassign.js b/tests/lib/rules/no-param-reassign.js
index 74fe41a87..a98a6dfe1 100644
--- a/tests/lib/rules/no-param-reassign.js
+++ b/tests/lib/rules/no-param-reassign.js
@@ -35,7 +35,12 @@ ruleTester.run("no-param-reassign", rule, {
         { code: "function foo(a) { ++a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
         { code: "function foo(a) { delete a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
         { code: "function foo(a, z) { a.b = 0; x.y = 0; }", options: [{ props: true, ignorePropertyModificationsFor: ["a", "x"] }] },
-        { code: "function foo(a) { a.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] }
+        { code: "function foo(a) { a.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
+        {
+            code: "function foo(a) { ({ [a]: variable } = value) }",
+            options: [{ props: true }],
+            parserOptions: { ecmaVersion: 6 }
+        }
     ],
 
     invalid: [
@@ -82,6 +87,18 @@ ruleTester.run("no-param-reassign", rule, {
             parserOptions: { ecmaVersion: 6 },
             options: [{ props: true, ignorePropertyModificationsFor: ["a"] }],
             errors: [{ message: "Assignment to property of function parameter 'bar'." }]
+        },
+        {
+            code: "function foo(bar) { ({foo: bar.a} = {}); }",
+            parserOptions: { ecmaVersion: 6 },
+            options: [{ props: true }],
+            errors: [{ message: "Assignment to property of function parameter 'bar'." }]
+        },
+        {
+            code: "function foo(a) { ({a} = obj); }",
+            parserOptions: { ecmaVersion: 6 },
+            options: [{ props: true }],
+            errors: [{ message: "Assignment to function parameter 'a'." }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-restricted-modules.js b/tests/lib/rules/no-restricted-modules.js
index ea4d5e1d4..cadf6bba6 100644
--- a/tests/lib/rules/no-restricted-modules.js
+++ b/tests/lib/rules/no-restricted-modules.js
@@ -26,11 +26,11 @@ ruleTester.run("no-restricted-modules", rule, {
         { code: "require(2)", options: ["crypto"] },
         { code: "require(foo)", options: ["crypto"] },
         { code: "var foo = bar('crypto');", options: ["crypto"] },
-        { code: "require(\"foo/bar\");", option: ["foo"] },
-        { code: "var withPaths = require(\"foo/bar\");", option: [{ paths: ["foo", "bar"] }] },
-        { code: "var withPatterns = require(\"foo/bar\");", option: [{ patterns: ["foo/c*"] }] },
-        { code: "var withPatternsAndPaths = require(\"foo/bar\");", option: [{ paths: ["foo"], patterns: ["foo/c*"] }] },
-        { code: "var withGitignores = require(\"foo/bar\");", option: [{ paths: ["foo"], patterns: ["foo/*", "!foo/bar"] }] }
+        { code: "require(\"foo/bar\");", options: ["foo"] },
+        { code: "var withPaths = require(\"foo/bar\");", options: [{ paths: ["foo", "bar"] }] },
+        { code: "var withPatterns = require(\"foo/bar\");", options: [{ patterns: ["foo/c*"] }] },
+        { code: "var withPatternsAndPaths = require(\"foo/bar\");", options: [{ paths: ["foo"], patterns: ["foo/c*"] }] },
+        { code: "var withGitignores = require(\"foo/bar\");", options: [{ paths: ["foo"], patterns: ["foo/*", "!foo/bar"] }] }
     ],
     invalid: [{
         code: "require(\"fs\")",
diff --git a/tests/lib/rules/no-restricted-properties.js b/tests/lib/rules/no-restricted-properties.js
index fca512cbc..e632663ee 100644
--- a/tests/lib/rules/no-restricted-properties.js
+++ b/tests/lib/rules/no-restricted-properties.js
@@ -108,7 +108,7 @@ ruleTester.run("no-restricted-properties", rule, {
             options: [{ object: "foo", property: "bar" }],
             parserOptions: { ecmaVersion: 6 }
         }, {
-            code: "let {baz: {bar: qux}} = foo;", property: "bar",
+            code: "let {baz: {bar: qux}} = foo;",
             options: [{ object: "foo", property: "bar" }],
             parserOptions: { ecmaVersion: 6 }
         }, {
diff --git a/tests/lib/rules/no-restricted-syntax.js b/tests/lib/rules/no-restricted-syntax.js
index 7547e302b..3a653a978 100644
--- a/tests/lib/rules/no-restricted-syntax.js
+++ b/tests/lib/rules/no-restricted-syntax.js
@@ -19,6 +19,8 @@ const ruleTester = new RuleTester();
 
 ruleTester.run("no-restricted-syntax", rule, {
     valid: [
+
+        // string format
         { code: "doSomething();" },
         { code: "var foo = 42;", options: ["ConditionalExpression"] },
         { code: "foo += 42;", options: ["VariableDeclaration", "FunctionExpression"] },
@@ -26,9 +28,19 @@ ruleTester.run("no-restricted-syntax", rule, {
         { code: "() => 5", options: ["ArrowFunctionExpression > BlockStatement"], parserOptions: { ecmaVersion: 6 } },
         { code: "({ foo: 1, bar: 2 })", options: ["Property > Literal.key"] },
         { code: "A: for (;;) break;", options: ["BreakStatement[label]"] },
-        { code: "function foo(bar, baz) {}", options: ["FunctionDeclaration[params.length>2]"] }
+        { code: "function foo(bar, baz) {}", options: ["FunctionDeclaration[params.length>2]"] },
+
+        //  object format
+        { code: "var foo = 42;", options: [{ selector: "ConditionalExpression" }] },
+        { code: "({ foo: 1, bar: 2 })", options: [{ selector: "Property > Literal.key" }] },
+        {
+            code: "({ foo: 1, bar: 2 })",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom error message." }]
+        }
     ],
     invalid: [
+
+        // string format
         {
             code: "var foo = 41;",
             options: ["VariableDeclaration"],
@@ -82,6 +94,30 @@ ruleTester.run("no-restricted-syntax", rule, {
             code: "function foo(bar, baz, qux) {}",
             options: ["FunctionDeclaration[params.length>2]"],
             errors: [{ message: "Using 'FunctionDeclaration[params.length>2]' is not allowed.", type: "FunctionDeclaration" }]
+        },
+
+        // object format
+        {
+            code: "var foo = 41;",
+            options: [{ selector: "VariableDeclaration" }],
+            errors: [{ message: "Using 'VariableDeclaration' is not allowed.", type: "VariableDeclaration" }]
+        },
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]" }],
+            errors: [{ message: "Using 'FunctionDeclaration[params.length>2]' is not allowed.", type: "FunctionDeclaration" }]
+        },
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom error message." }],
+            errors: [{ message: "custom error message.", type: "FunctionDeclaration" }]
+        },
+
+        // with object format, the custom message may contain the string '{{selector}}'
+        {
+            code: "function foo(bar, baz, qux) {}",
+            options: [{ selector: "FunctionDeclaration[params.length>2]", message: "custom message with {{selector}}" }],
+            errors: [{ message: "custom message with {{selector}}", type: "FunctionDeclaration" }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-unexpected-multiline.js b/tests/lib/rules/no-unexpected-multiline.js
index eb0e9f92b..3a5dee1e2 100644
--- a/tests/lib/rules/no-unexpected-multiline.js
+++ b/tests/lib/rules/no-unexpected-multiline.js
@@ -47,60 +47,79 @@ ruleTester.run("no-unexpected-multiline", rule, {
     invalid: [
         {
             code: "var a = b\n(x || y).doSomething()",
-            line: 2,
-            column: 1,
-            errors: [{ message: "Unexpected newline between function and ( of function call." }]
+            errors: [{
+                message: "Unexpected newline between function and ( of function call.",
+                line: 2,
+                column: 1
+
+            }]
         },
         {
             code: "var a = (a || b)\n(x || y).doSomething()",
-            line: 2,
-            column: 1,
-            errors: [{ message: "Unexpected newline between function and ( of function call." }]
+            errors: [{
+                line: 2,
+                column: 1,
+                message: "Unexpected newline between function and ( of function call."
+            }]
         },
         {
             code: "var a = (a || b)\n(x).doSomething()",
-            line: 2,
-            column: 1,
-            errors: [{ message: "Unexpected newline between function and ( of function call." }]
+            errors: [{
+                line: 2,
+                column: 1,
+                message: "Unexpected newline between function and ( of function call."
+            }]
         },
         {
             code: "var a = b\n[a, b, c].forEach(doSomething)",
-            line: 2,
-            column: 1,
-            errors: [{ message: "Unexpected newline between object and [ of property access." }]
+            errors: [{
+                line: 2,
+                column: 1,
+                message: "Unexpected newline between object and [ of property access."
+            }]
         },
         {
             code: "var a = b\n    (x || y).doSomething()",
-            line: 2,
-            column: 5,
-            errors: [{ message: "Unexpected newline between function and ( of function call." }]
+            errors: [{
+                line: 2,
+                column: 5,
+                message: "Unexpected newline between function and ( of function call."
+            }]
         },
         {
             code: "var a = b\n  [a, b, c].forEach(doSomething)",
-            line: 2,
-            column: 3,
-            errors: [{ message: "Unexpected newline between object and [ of property access." }]
+            errors: [{
+                line: 2,
+                column: 3,
+                message: "Unexpected newline between object and [ of property access."
+            }]
         },
         {
             code: "let x = function() {}\n `hello`",
             parserOptions: { ecmaVersion: 6 },
-            line: 1,
-            column: 9,
-            errors: [{ message: "Unexpected newline between template tag and template literal." }]
+            errors: [{
+                line: 1,
+                column: 9,
+                message: "Unexpected newline between template tag and template literal."
+            }]
         },
         {
             code: "let x = function() {}\nx\n`hello`",
             parserOptions: { ecmaVersion: 6 },
-            line: 2,
-            column: 1,
-            errors: [{ message: "Unexpected newline between template tag and template literal." }]
+            errors: [{
+                line: 2,
+                column: 1,
+                message: "Unexpected newline between template tag and template literal."
+            }]
         },
         {
             code: "x\n.y\nz\n`Invalid Test Case`",
             parserOptions: { ecmaVersion: 6 },
-            line: 3,
-            column: 1,
-            errors: [{ message: "Unexpected newline between template tag and template literal." }]
+            errors: [{
+                line: 3,
+                column: 1,
+                message: "Unexpected newline between template tag and template literal."
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-useless-computed-key.js b/tests/lib/rules/no-useless-computed-key.js
index 61c535075..c825579fc 100644
--- a/tests/lib/rules/no-useless-computed-key.js
+++ b/tests/lib/rules/no-useless-computed-key.js
@@ -87,6 +87,81 @@ ruleTester.run("no-useless-computed-key", rule, {
             errors: [{
                 message: "Unnecessarily computed property ['x'] found.", type: "Property"
             }]
+        }, {
+            code: "({ get[.2]() {} })",
+            output: "({ get.2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [.2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ set[.2](value) {} })",
+            output: "({ set.2(value) {} })",
+            errors: [{
+                message: "Unnecessarily computed property [.2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ async[.2]() {} })",
+            output: "({ async.2() {} })",
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{
+                message: "Unnecessarily computed property [.2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ [2]() {} })",
+            output: "({ 2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ get [2]() {} })",
+            output: "({ get 2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ set [2](value) {} })",
+            output: "({ set 2(value) {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ async [2]() {} })",
+            output: "({ async 2() {} })",
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ get[2]() {} })",
+            output: "({ get 2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ set[2](value) {} })",
+            output: "({ set 2(value) {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ async[2]() {} })",
+            output: "({ async 2() {} })",
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
+        }, {
+            code: "({ get['foo']() {} })",
+            output: "({ get'foo'() {} })",
+            errors: [{
+                message: "Unnecessarily computed property ['foo'] found.", type: "Property"
+            }]
+        }, {
+            code: "({ *[2]() {} })",
+            output: "({ *2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js
index 8ef707d52..d961849ae 100644
--- a/tests/lib/rules/object-shorthand.js
+++ b/tests/lib/rules/object-shorthand.js
@@ -973,6 +973,17 @@ ruleTester.run("object-shorthand", rule, {
             `,
             options: ["always", { avoidExplicitReturnArrows: true }],
             errors: [METHOD_ERROR]
+        },
+        {
+            code: "({ a: (function(){ return foo; }) })",
+            output: "({ a(){ return foo; } })",
+            errors: [METHOD_ERROR]
+        },
+        {
+            code: "({ a: (() => { return foo; }) })",
+            output: "({ a() { return foo; } })",
+            options: ["always", { avoidExplicitReturnArrows: true }],
+            errors: [METHOD_ERROR]
         }
     ]
 });
diff --git a/tests/lib/rules/operator-assignment.js b/tests/lib/rules/operator-assignment.js
index e0f3e4e13..fb1ff889e 100644
--- a/tests/lib/rules/operator-assignment.js
+++ b/tests/lib/rules/operator-assignment.js
@@ -81,7 +81,8 @@ ruleTester.run("operator-assignment", rule, {
         "x = x === y",
         "x = x !== y",
         "x = x && y",
-        "x = x || y"
+        "x = x || y",
+        "x = x * y + z"
     ],
 
     invalid: [{
@@ -154,6 +155,16 @@ ruleTester.run("operator-assignment", rule, {
         output: "x += y",
         options: ["always"],
         errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x = x + (y)",
+        output: "x += (y)",
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x += (y)",
+        output: "x = x + (y)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
     }, {
         code: "x += y",
         output: "x = x + y",
@@ -204,6 +215,31 @@ ruleTester.run("operator-assignment", rule, {
         output: "foo = foo ** bar",
         options: ["never"],
         errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo *= bar + 1",
+        output: "foo = foo * (bar + 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo -= bar - baz",
+        output: "foo = foo - (bar - baz)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo += bar + baz",
+        output: "foo = foo + (bar + baz)", // addition is not associative in JS, e.g. (1 + 2) + '3' !== 1 + (2 + '3')
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo += bar = 1",
+        output: "foo = foo + (bar = 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo *= (bar + 1)",
+        output: "foo = foo * (bar + 1)",
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
     }]
 
 });
diff --git a/tests/lib/rules/padded-blocks.js b/tests/lib/rules/padded-blocks.js
index c9208183b..a691e1108 100644
--- a/tests/lib/rules/padded-blocks.js
+++ b/tests/lib/rules/padded-blocks.js
@@ -39,23 +39,14 @@ ruleTester.run("padded-blocks", rule, {
         { code: "{\n\na();\n\n/* comment */ }", options: ["always"] },
         { code: "{\n\na();\n\n/* comment */ }", options: [{ blocks: "always" }] },
 
-        // Ignore switches by default
-        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["always"] },
-        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["never"] },
-
-        // Ignore block statements if not configured
-        { code: "{\na();\n}", options: [{ switches: "always" }] },
-        { code: "{\n\na();\n\n}", options: [{ switches: "never" }] },
-
         { code: "switch (a) {}", options: [{ switches: "always" }] },
+        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: ["always"] },
         { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: [{ switches: "always" }] },
         { code: "switch (a) {\n\n//comment\ncase 0: foo();//comment\n\n}", options: [{ switches: "always" }] },
         { code: "switch (a) {//coment\n\ncase 0: foo();\ncase 1: bar();\n\n/* comment */}", options: [{ switches: "always" }] },
 
-        // Ignore classes by default
-        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 } },
         { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 } },
-
+        { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: ["always"] },
         { code: "class A{}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
         { code: "class A{\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
         { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "always" }] },
@@ -75,8 +66,27 @@ ruleTester.run("padded-blocks", rule, {
         { code: "{\n\n// comment\nif (\n// comment\n a) {}\n\n }", options: ["always"] },
         { code: "{\n// comment\nif (\n// comment\n a) {}\n }", options: ["never"] },
         { code: "{\n// comment\nif (\n// comment\n a) {}\n }", options: [{ blocks: "never" }] },
+
+        { code: "switch (a) {\ncase 0: foo();\n}", options: ["never"] },
         { code: "switch (a) {\ncase 0: foo();\n}", options: [{ switches: "never" }] },
-        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "never" }] }
+
+
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: ["never"] },
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ classes: "never" }] },
+
+        // Ignore block statements if not configured
+        { code: "{\na();\n}", options: [{ switches: "always" }] },
+        { code: "{\n\na();\n\n}", options: [{ switches: "never" }] },
+
+        // Ignore switch statements if not configured
+        { code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}", options: [{ blocks: "always", classes: "always" }] },
+        { code: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}", options: [{ blocks: "never", classes: "never" }] },
+
+
+        // Ignore class statements if not configured
+        { code: "class A{\nfoo(){}\n}", parserOptions: { ecmaVersion: 6 }, options: [{ blocks: "always" }] },
+        { code: "class A{\n\nfoo(){}\n\n}", parserOptions: { ecmaVersion: 6 }, options: [{ blocks: "never" }] }
+
     ],
     invalid: [
         {
@@ -214,6 +224,23 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}",
+            output: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}",
+            options: ["always"],
+            errors: [
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 1,
+                    column: 12
+                },
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 4,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "switch (a) {\ncase 0: foo();\ncase 1: bar();\n}",
             output: "switch (a) {\n\ncase 0: foo();\ncase 1: bar();\n\n}",
@@ -248,6 +275,24 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "class A {\nconstructor(){}\n}",
+            output: "class A {\n\nconstructor(){}\n\n}",
+            parserOptions: { ecmaVersion: 6 },
+            options: ["always"],
+            errors: [
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 1,
+                    column: 9
+                },
+                {
+                    message: ALWAYS_MESSAGE,
+                    line: 3,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "class A {\nconstructor(){}\n}",
             output: "class A {\n\nconstructor(){}\n\n}",
@@ -416,6 +461,23 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "switch (a) {\n\ncase 0: foo();\n\n}",
+            output: "switch (a) {\ncase 0: foo();\n}",
+            options: ["never"],
+            errors: [
+                {
+                    message: NEVER_MESSAGE,
+                    line: 1,
+                    column: 12
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 5,
+                    column: 1
+                }
+            ]
+        },
         {
             code: "switch (a) {\n\ncase 0: foo();\n}",
             output: "switch (a) {\ncase 0: foo();\n}",
@@ -440,6 +502,30 @@ ruleTester.run("padded-blocks", rule, {
                 }
             ]
         },
+        {
+            code: "class A {\n\nconstructor(){\n\nfoo();\n\n}\n\n}",
+            output: "class A {\nconstructor(){\nfoo();\n}\n}",
+            parserOptions: { ecmaVersion: 6 },
+            options: ["never"],
+            errors: [
+                {
+                    message: NEVER_MESSAGE,
+                    line: 1
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 3
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 7
+                },
+                {
+                    message: NEVER_MESSAGE,
+                    line: 9
+                }
+            ]
+        },
         {
             code: "class A {\n\nconstructor(){\n\nfoo();\n\n}\n\n}",
             output: "class A {\nconstructor(){\n\nfoo();\n\n}\n}",
diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js
index 75821f95a..984649cb4 100644
--- a/tests/lib/rules/prefer-const.js
+++ b/tests/lib/rules/prefer-const.js
@@ -10,6 +10,7 @@
 //------------------------------------------------------------------------------
 
 const rule = require("../../../lib/rules/prefer-const"),
+    fixtureParser = require("../../fixtures/fixture-parser"),
     RuleTester = require("../../../lib/testers/rule-tester");
 
 //------------------------------------------------------------------------------
@@ -88,6 +89,18 @@ ruleTester.run("prefer-const", rule, {
             options: [{ destructuring: "all" }]
         },
 
+        // https://github.com/eslint/eslint/issues/8187
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            options: [{ destructuring: "all" }],
+            parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
+        },
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            options: [{ destructuring: "all" }],
+            parser: fixtureParser("babel-eslint5/destructuring-object-spread")
+        },
+
         // ignoreReadBeforeAssign
         {
             code: "let x; function foo() { bar(x); } x = 0;",
@@ -290,6 +303,22 @@ ruleTester.run("prefer-const", rule, {
             errors: [{ message: "'c' is never reassigned. Use 'const' instead.", type: "Identifier" }]
         },
 
+        // https://github.com/eslint/eslint/issues/8187
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            output: null,
+            options: [{ destructuring: "any" }],
+            parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
+            errors: [{ message: "'name' is never reassigned. Use 'const' instead.", type: "Identifier", column: 7 }]
+        },
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            output: null,
+            options: [{ destructuring: "any" }],
+            parser: fixtureParser("babel-eslint5/destructuring-object-spread"),
+            errors: [{ message: "'name' is never reassigned. Use 'const' instead.", type: "Identifier", column: 7 }]
+        },
+
         // Warnings are located at declaration if there are reading references before assignments.
         {
             code: "let x; function foo() { bar(x); } x = 0;",
diff --git a/tests/lib/rules/quotes.js b/tests/lib/rules/quotes.js
index 98ccd043e..3201e594c 100644
--- a/tests/lib/rules/quotes.js
+++ b/tests/lib/rules/quotes.js
@@ -68,8 +68,10 @@ ruleTester.run("quotes", rule, {
         { code: "import a from \"a\"; import b from 'b';", options: ["backtick"], parserOptions: { sourceType: "module" } },
         { code: "export * from \"a\"; export * from 'b';", options: ["backtick"], parserOptions: { sourceType: "module" } },
 
-        // `backtick` should not warn property names (not computed).
-        { code: "var obj = {\"key0\": 0, 'key1': 1};", options: ["backtick"], parserOptions: { ecmaVersion: 6 } }
+        // `backtick` should not warn property/method names (not computed).
+        { code: "var obj = {\"key0\": 0, 'key1': 1};", options: ["backtick"], parserOptions: { ecmaVersion: 6 } },
+        { code: "class Foo { 'bar'(){} }", options: ["backtick"], parserOptions: { ecmaVersion: 6 } },
+        { code: "class Foo { static ''(){} }", options: ["backtick"], parserOptions: { ecmaVersion: 6 } }
     ],
     invalid: [
         {
@@ -205,7 +207,7 @@ ruleTester.run("quotes", rule, {
             errors: [{ message: "Strings must use backtick.", type: "Literal" }]
         },
 
-        // `backtick` should not warn computed property names.
+        // `backtick` should warn computed property names.
         {
             code: "var obj = {[\"key0\"]: 0, ['key1']: 1};",
             output: "var obj = {[`key0`]: 0, [`key1`]: 1};",
@@ -216,6 +218,16 @@ ruleTester.run("quotes", rule, {
                 { message: "Strings must use backtick.", type: "Literal" }
             ]
         },
+        {
+            code: "class Foo { ['a'](){} static ['b'](){} }",
+            output: "class Foo { [`a`](){} static [`b`](){} }",
+            options: ["backtick"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Strings must use backtick.", type: "Literal" },
+                { message: "Strings must use backtick.", type: "Literal" }
+            ]
+        },
 
         // https://github.com/eslint/eslint/issues/7084
         {
diff --git a/tests/lib/rules/space-before-function-paren.js b/tests/lib/rules/space-before-function-paren.js
index 26180be5f..5e37dfd4e 100644
--- a/tests/lib/rules/space-before-function-paren.js
+++ b/tests/lib/rules/space-before-function-paren.js
@@ -8,8 +8,9 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const rule = require("../../../lib/rules/space-before-function-paren"),
-    RuleTester = require("../../../lib/testers/rule-tester");
+const rule = require("../../../lib/rules/space-before-function-paren");
+const RuleTester = require("../../../lib/testers/rule-tester");
+const baseParser = require("../../fixtures/fixture-parser");
 
 //------------------------------------------------------------------------------
 // Tests
@@ -95,6 +96,10 @@ ruleTester.run("space-before-function-paren", rule, {
         { code: "var bar = function foo () {}",
             options: [{ named: "ignore", anonymous: "always" }]
         },
+        {
+            code: "type TransformFunction = (el: ASTElement, code: string) => string;",
+            parser: baseParser("babel-eslint7", "function-type-annotation")
+        },
 
         // Async arrow functions
         { code: "() => 1", parserOptions: { ecmaVersion: 6 } },
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-util.js
index 452ca06b2..47175848f 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-util.js
@@ -144,6 +144,16 @@ describe("globUtil", () => {
             assert.deepEqual(result, ["one-js-file/example.js"]);
         });
 
+        it("should ignore empty patterns", () => {
+            const patterns = [""];
+            const opts = {
+                cwd: getFixturePath()
+            };
+            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+
+            assert.deepEqual(result, []);
+        });
+
     });
 
     describe("listFilesToProcess()", () => {
diff --git a/tests/lib/util/node-event-generator.js b/tests/lib/util/node-event-generator.js
index 7c875ef18..8cea6c47b 100644
--- a/tests/lib/util/node-event-generator.js
+++ b/tests/lib/util/node-event-generator.js
@@ -260,6 +260,7 @@ describe("NodeEventGenerator", () => {
                 "FooStatement",
                 "[name = 'foo']",
                 "[name='foo']",
+                "[name ='foo']",
                 "Identifier[name='foo']",
                 "[name='foo'][name.length=3]",
                 ":not(Program, ExpressionStatement)",
@@ -277,6 +278,7 @@ describe("NodeEventGenerator", () => {
                 ["ExpressionStatement > Identifier", ast.body[0].expression], // 0 pseudoclasses, 2 identifiers
                 ["Identifier, ReturnStatement", ast.body[0].expression], // 0 pseudoclasses, 2 identifiers
                 ["[name = 'foo']", ast.body[0].expression], // 1 pseudoclass, 0 identifiers
+                ["[name ='foo']", ast.body[0].expression], // 1 pseudoclass, 0 identifiers
                 ["[name='foo']", ast.body[0].expression], // 1 pseudoclass, 0 identifiers
                 ["ExpressionStatement > [name='foo']", ast.body[0].expression], // 1 attribute, 1 identifier
                 ["Identifier[name='foo']", ast.body[0].expression], // 1 attribute, 1 identifier
@@ -284,6 +286,24 @@ describe("NodeEventGenerator", () => {
                 ["[name='foo'][name.length=3]", ast.body[0].expression] // 2 attributes, 0 identifiers
             ]
         );
+
+        assertEmissions(
+            "foo(); bar; baz;",
+            ["CallExpression, [name='bar']"],
+            ast => [
+                ["CallExpression, [name='bar']", ast.body[0].expression],
+                ["CallExpression, [name='bar']", ast.body[1].expression]
+            ]
+        );
+
+        assertEmissions(
+            "foo; bar;",
+            ["[name.length=3]:exit"],
+            ast => [
+                ["[name.length=3]:exit", ast.body[0].expression],
+                ["[name.length=3]:exit", ast.body[1].expression]
+            ]
+        );
     });
 
     describe("parsing an invalid selector", () => {
diff --git a/tests/lib/util/path-util.js b/tests/lib/util/path-util.js
index 455294b99..cd3fd650a 100644
--- a/tests/lib/util/path-util.js
+++ b/tests/lib/util/path-util.js
@@ -74,7 +74,7 @@ describe("pathUtil", () => {
             const filePath = "file/path.js";
             const basePath = "/absolute/file";
 
-            sinon.stub(process, "cwd", () => "/absolute/");
+            sinon.stub(process, "cwd").returns("/absolute/");
             const result = pathUtil.getRelativePath(filePath, basePath);
 
             assert.equal(result, "path.js");