Repository: eslint/eslint
Pull request #12091 (2019-08-12 14:29:14)

New: noInlineConfig setting (refs eslint/rfcs#22)
**What is the purpose of this pull request? (put an "X" next to item)**

[X] Add something to the core

**What changes did you make? (Give an overview)**

This PR implements a part of eslint/rfcs#22, `noInlineConfig` setting.

Also, this PR fixes a bug that `--no-inline-config` didn't disable `eslint-env` comments.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular.


mysticatea: I'm not sure why `commit-message` failed.
aladdin-add: I think it's failing just as it does not support fixing cross-repo issue.  :)
mysticatea: I have updated this PR.

- Fix typo
- Add tests for line comments
- Add config name what `noInlineConfig` came from

Patch:
diff --git a/conf/config-schema.js b/conf/config-schema.js
index 36f3c27de..d89bf0f58 100644
--- a/conf/config-schema.js
+++ b/conf/config-schema.js
@@ -20,6 +20,7 @@ const baseConfigProperties = {
     processor: { type: "string" },
     rules: { type: "object" },
     settings: { type: "object" },
+    noInlineConfig: { type: "boolean" },
 
     ecmaFeatures: { type: "object" } // deprecated; logs a warning when used
 };
diff --git a/docs/developer-guide/scope-manager-interface.md b/docs/developer-guide/scope-manager-interface.md
index 08986caa2..3ee5b23d3 100644
--- a/docs/developer-guide/scope-manager-interface.md
+++ b/docs/developer-guide/scope-manager-interface.md
@@ -28,7 +28,7 @@ This document was written based on the implementation of [eslint-scope](https://
     * `node` (`ASTNode`) ... An AST node to get their scope.
     * `inner` (`boolean`) ... If the node has multiple scope, this returns the outermost scope normally. If `inner` is `true` then this returns the innermost scope. Default is `false`.
 * **Return type:** `Scope | null`
-* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope and `TDZ` scope. If the node does not have their scope, this returns `null`.
+* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope. If the node does not have their scope, this returns `null`.
 
 #### getDeclaredVariables(node)
 
@@ -77,7 +77,7 @@ Those members are defined but not used in ESLint.
 #### type
 
 * **Type:** `string`
-* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`, `"TDZ"`
+* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`
 
 #### isStrict
 
@@ -334,7 +334,7 @@ Those members are defined but not used in ESLint.
 #### type
 
 * **Type:** `string`
-* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, `"TDZ"`, and `"Variable"`.
+* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, and `"Variable"`.
 
 #### name
 
@@ -354,7 +354,6 @@ Those members are defined but not used in ESLint.
 | `"ImplicitGlobalVariable"` | `Program`
 | `"ImportBinding"`          | `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`
 | `"Parameter"`              | `FunctionDeclaration`, `FunctionExpression`, or `ArrowFunctionExpression`
-| `"TDZ"`                    | ?
 | `"Variable"`               | `VariableDeclarator`
 
 #### parent
@@ -370,7 +369,6 @@ Those members are defined but not used in ESLint.
 | `"ImplicitGlobalVariable"` | `null`
 | `"ImportBinding"`          | `ImportDeclaration`
 | `"Parameter"`              | `null`
-| `"TDZ"`                    | `null`
 | `"Variable"`               | `VariableDeclaration`
 
 ### Deprecated members
diff --git a/docs/rules/accessor-pairs.md b/docs/rules/accessor-pairs.md
index 1cbf7c9ef..207eedeac 100644
--- a/docs/rules/accessor-pairs.md
+++ b/docs/rules/accessor-pairs.md
@@ -143,6 +143,27 @@ Object.defineProperty(o, 'c', {
 
 ```
 
+## Known Limitations
+
+Due to the limits of static analysis, this rule does not account for possible side effects and in certain cases
+might not report a missing pair for a getter/setter that has a computed key, like in the following example:
+
+```js
+/*eslint accessor-pairs: "error"*/
+
+var a = 1;
+
+// no warnings
+var o = {
+    get [a++]() {
+        return this.val;
+    },
+    set [a++](value) {
+        this.val = value;
+    }
+};
+```
+
 ## When Not To Use It
 
 You can turn this rule off if you are not concerned with the simultaneous presence of setters and getters on objects.
diff --git a/docs/rules/function-call-argument-newline.md b/docs/rules/function-call-argument-newline.md
new file mode 100644
index 000000000..bdb98807f
--- /dev/null
+++ b/docs/rules/function-call-argument-newline.md
@@ -0,0 +1,202 @@
+# enforce line breaks between arguments of a function call (function-call-argument-newline)
+
+A number of style guides require or disallow line breaks between arguments of a function call.
+
+## Rule Details
+
+This rule enforces line breaks between arguments of a function call.
+
+## Options
+
+This rule has a string option:
+
+* `"always"` (default) requires line breaks between arguments
+* `"never"` disallows line breaks between arguments
+* `"consistent"` requires consistent usage of line breaks between arguments
+
+
+### always
+
+Examples of **incorrect** code for this rule with the default `"always"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "always"]*/
+
+foo("one", "two", "three");
+
+bar("one", "two", {
+    one: 1,
+    two: 2
+});
+
+baz("one", "two", (x) => {
+    console.log(x);
+});
+```
+
+Examples of **correct** code for this rule with the default `"always"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "always"]*/
+
+foo(
+    "one",
+    "two",
+    "three"
+);
+
+bar(
+    "one",
+    "two",
+    { one: 1, two: 2 }
+);
+// or
+bar(
+    "one",
+    "two",
+    {
+        one: 1,
+        two: 2
+    }
+);
+
+baz(
+    "one",
+    "two",
+    (x) => {
+        console.log(x);
+    }
+);
+```
+
+
+### never
+
+Examples of **incorrect** code for this rule with the default `"never"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "never"]*/
+
+foo(
+    "one",
+    "two", "three"
+);
+
+bar(
+    "one",
+    "two", {
+        one: 1,
+        two: 2
+    }
+);
+
+baz(
+    "one",
+    "two", (x) => {
+        console.log(x);
+    }
+);
+```
+
+Examples of **correct** code for this rule with the `"never"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "never"]*/
+
+foo("one", "two", "three");
+// or
+foo(
+    "one", "two", "three"
+);
+
+bar("one", "two", { one: 1, two: 2 });
+// or
+bar("one", "two", {
+    one: 1,
+    two: 2
+});
+
+baz("one", "two", (x) => {
+    console.log(x);
+});
+```
+
+### consistent
+
+Examples of **incorrect** code for this rule with the default `"consistent"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "consistent"]*/
+
+foo("one", "two",
+    "three");
+//or
+foo("one",
+    "two", "three");
+
+bar("one", "two",
+    { one: 1, two: 2}
+);
+
+baz("one", "two",
+    (x) => { console.log(x); }
+);
+```
+
+Examples of **correct** code for this rule with the default `"consistent"` option:
+
+```js
+/*eslint function-call-argument-newline: ["error", "consistent"]*/
+
+foo("one", "two", "three");
+// or
+foo(
+    "one",
+    "two",
+    "three"
+);
+
+bar("one", "two", {
+    one: 1,
+    two: 2
+});
+// or
+bar(
+    "one",
+    "two",
+    { one: 1, two: 2 }
+);
+// or
+bar(
+    "one",
+    "two",
+    {
+        one: 1,
+        two: 2
+    }
+);
+
+baz("one", "two", (x) => {
+    console.log(x);
+});
+// or
+baz(
+    "one",
+    "two",
+    (x) => {
+        console.log(x);
+    }
+);
+```
+
+
+## When Not To Use It
+
+If you don't want to enforce line breaks between arguments, don't enable this rule.
+
+## Related Rules
+
+* [function-paren-newline](function-paren-newline.md)
+* [func-call-spacing](func-call-spacing.md)
+* [object-property-newline](object-property-newline.md)
+* [array-element-newline](array-element-newline.md)
diff --git a/docs/rules/no-mixed-operators.md b/docs/rules/no-mixed-operators.md
index 3c0bb2fab..3206d18fb 100644
--- a/docs/rules/no-mixed-operators.md
+++ b/docs/rules/no-mixed-operators.md
@@ -5,6 +5,8 @@ This rule warns when different operators are used consecutively without parenthe
 
 ```js
 var foo = a && b || c || d;    /*BAD: Unexpected mix of '&&' and '||'.*/
+var foo = a && b ? c : d;      /*BAD: Unexpected mix of '&&' and '?:'.*/
+var foo = (a && b) ? c : d;    /*GOOD*/
 var foo = (a && b) || c || d;  /*GOOD*/
 var foo = a && (b || c || d);  /*GOOD*/
 ```
@@ -23,10 +25,21 @@ will generate
 1:18  Unexpected mix of '&&' and '||'. (no-mixed-operators)
 ```
 
+```js
+var foo = a && b ? c : d;
+```
+
+will generate
+
+```sh
+1:13  Unexpected mix of '&&' and '?:'. (no-mixed-operators)
+1:18  Unexpected mix of '&&' and '?:'. (no-mixed-operators)
+```
+
 
 ## Rule Details
 
-This rule checks `BinaryExpression` and `LogicalExpression`.
+This rule checks `BinaryExpression`, `LogicalExpression` and `ConditionalExpression`.
 
 This rule may conflict with [no-extra-parens](no-extra-parens.md) rule.
 If you use both this and [no-extra-parens](no-extra-parens.md) rule together, you need to use the `nestedBinaryExpressions` option of [no-extra-parens](no-extra-parens.md) rule.
@@ -75,7 +88,8 @@ var foo = (a + b) * c;
 
 This rule has 2 options.
 
-* `groups` (`string[][]`) - specifies operator groups to be checked. The `groups` option is a list of groups, and a group is a list of binary operators. Default operator groups are defined as arithmetic, bitwise, comparison, logical, and relational operators.
+* `groups` (`string[][]`) - specifies operator groups to be checked. The `groups` option is a list of groups, and a group is a list of binary operators. Default operator groups are defined as arithmetic, bitwise, comparison, logical, and relational operators. Note: Ternary operator(?:) can be part of any group and by default is allowed to be mixed with other operators.
+
 * `allowSamePrecedence` (`boolean`) - specifies whether to allow mixed operators if they are of equal precedence. Default is `true`.
 
 ### groups
@@ -87,6 +101,7 @@ The following operators can be used in `groups` option:
 * Comparison Operators: `"=="`, `"!="`, `"==="`, `"!=="`, `">"`, `">="`, `"<"`, `"<="`
 * Logical Operators: `"&&"`, `"||"`
 * Relational Operators: `"in"`, `"instanceof"`
+* Ternary Operator: `?:`
 
 Now, consider the following group configuration: `{"groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["&&", "||"]]}`.
 There are 2 groups specified in this configuration: bitwise operators and logical operators.
@@ -102,6 +117,12 @@ var foo = a && b < 0 || c > 0 || d + 1 === 0;
 var foo = a & b | c;
 ```
 
+```js
+/*eslint no-mixed-operators: ["error", {"groups": [["&&", "||", "?:"]]}]*/
+
+var foo = a || b ? c : d;
+```
+
 Examples of **correct** code for this rule with `{"groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["&&", "||"]]}` option:
 
 ```js
@@ -118,6 +139,13 @@ var foo = a + (b * c);
 var foo = (a + b) * c;
 ```
 
+```js
+/*eslint no-mixed-operators: ["error", {"groups": [["&&", "||", "?:"]]}]*/
+
+var foo = (a || b) ? c : d;
+var foo = a || (b ? c : d);
+```
+
 ### allowSamePrecedence
 
 Examples of **correct** code for this rule with `{"allowSamePrecedence": true}` option:
diff --git a/lib/cli-engine/config-array-factory.js b/lib/cli-engine/config-array-factory.js
index 95430c358..0b2ed07b6 100644
--- a/lib/cli-engine/config-array-factory.js
+++ b/lib/cli-engine/config-array-factory.js
@@ -526,6 +526,7 @@ class ConfigArrayFactory {
             env,
             extends: extend,
             globals,
+            noInlineConfig,
             parser: parserName,
             parserOptions,
             plugins: pluginList,
@@ -567,6 +568,7 @@ class ConfigArrayFactory {
             criteria: null,
             env,
             globals,
+            noInlineConfig,
             parser,
             parserOptions,
             plugins,
diff --git a/lib/cli-engine/config-array/config-array.js b/lib/cli-engine/config-array/config-array.js
index 5c7aaa334..0859868d8 100644
--- a/lib/cli-engine/config-array/config-array.js
+++ b/lib/cli-engine/config-array/config-array.js
@@ -54,6 +54,7 @@ const { ExtractedConfig } = require("./extracted-config");
  * @property {InstanceType<OverrideTester>|null} criteria The tester for the `files` and `excludedFiles` of this config element.
  * @property {Record<string, boolean>|undefined} env The environment settings.
  * @property {Record<string, GlobalConf>|undefined} globals The global variable settings.
+ * @property {boolean|undefined} noInlineConfig The flag that disables directive comments.
  * @property {DependentParser|undefined} parser The parser loader.
  * @property {Object|undefined} parserOptions The parser options.
  * @property {Record<string, DependentPlugin>|undefined} plugins The plugin loaders.
@@ -250,6 +251,12 @@ function createConfig(instance, indices) {
             config.processor = element.processor;
         }
 
+        // Adopt the noInlineConfig which was found at first.
+        if (config.noInlineConfig === void 0 && element.noInlineConfig !== void 0) {
+            config.noInlineConfig = element.noInlineConfig;
+            config.configNameOfNoInlineConfig = element.name;
+        }
+
         // Merge others.
         mergeWithoutOverwrite(config.env, element.env);
         mergeWithoutOverwrite(config.globals, element.globals);
diff --git a/lib/cli-engine/config-array/extracted-config.js b/lib/cli-engine/config-array/extracted-config.js
index 377cc0fa9..53208c16e 100644
--- a/lib/cli-engine/config-array/extracted-config.js
+++ b/lib/cli-engine/config-array/extracted-config.js
@@ -29,6 +29,12 @@
 class ExtractedConfig {
     constructor() {
 
+        /**
+         * The config name what `noInlineConfig` setting came from.
+         * @type {string}
+         */
+        this.configNameOfNoInlineConfig = "";
+
         /**
          * Environments.
          * @type {Record<string, boolean>}
@@ -41,6 +47,12 @@ class ExtractedConfig {
          */
         this.globals = {};
 
+        /**
+         * The flag that disables directive comments.
+         * @type {boolean|undefined}
+         */
+        this.noInlineConfig = void 0;
+
         /**
          * Parser definition.
          * @type {DependentParser|null}
@@ -84,7 +96,10 @@ class ExtractedConfig {
      */
     toCompatibleObjectAsConfigFileContent() {
         const {
-            processor: _ignore, // eslint-disable-line no-unused-vars
+            /* eslint-disable no-unused-vars */
+            configNameOfNoInlineConfig: _ignore1,
+            processor: _ignore2,
+            /* eslint-enable no-unused-vars */
             ...config
         } = this;
 
diff --git a/lib/init/npm-utils.js b/lib/init/npm-utils.js
index 26e78406f..3a680aae9 100644
--- a/lib/init/npm-utils.js
+++ b/lib/init/npm-utils.js
@@ -135,7 +135,7 @@ function check(packages, opt) {
  * Check whether node modules are included in the dependencies of a project's
  * package.json.
  *
- * Convienience wrapper around check().
+ * Convenience wrapper around check().
  *
  * @param   {string[]} packages  Array of node modules to check.
  * @param   {string}   rootDir   The directory contianing a package.json
@@ -150,7 +150,7 @@ function checkDeps(packages, rootDir) {
  * Check whether node modules are included in the devDependencies of a project's
  * package.json.
  *
- * Convienience wrapper around check().
+ * Convenience wrapper around check().
  *
  * @param   {string[]} packages  Array of node modules to check.
  * @returns {Object}             An object whose keys are the module names
diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index a49d85085..d367cef6c 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -198,14 +198,20 @@ function createMissingRuleMessage(ruleId) {
 /**
  * creates a linting problem
  * @param {Object} options to create linting error
- * @param {string} options.ruleId the ruleId to report
- * @param {Object} options.loc the loc to report
- * @param {string} options.message the error message to report
- * @returns {Problem} created problem, returns a missing-rule problem if only provided ruleId.
+ * @param {string} [options.ruleId] the ruleId to report
+ * @param {Object} [options.loc] the loc to report
+ * @param {string} [options.message] the error message to report
+ * @param {string} [options.severity] the error message to report
+ * @returns {LintMessage} created problem, returns a missing-rule problem if only provided ruleId.
  * @private
  */
 function createLintingProblem(options) {
-    const { ruleId, loc = DEFAULT_ERROR_LOC, message = createMissingRuleMessage(options.ruleId) } = options;
+    const {
+        ruleId = null,
+        loc = DEFAULT_ERROR_LOC,
+        message = createMissingRuleMessage(options.ruleId),
+        severity = 2
+    } = options;
 
     return {
         ruleId,
@@ -214,7 +220,7 @@ function createLintingProblem(options) {
         column: loc.start.column + 1,
         endLine: loc.end.line,
         endColumn: loc.end.column + 1,
-        severity: 2,
+        severity,
         nodeType: null
     };
 }
@@ -257,10 +263,11 @@ function createDisableDirectives(options) {
  * @param {string} filename The file being checked.
  * @param {ASTNode} ast The top node of the AST.
  * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
+ * @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
  * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
  * A collection of the directive comments that were found, along with any problems that occurred when parsing
  */
-function getDirectiveComments(filename, ast, ruleMapper) {
+function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
     const configuredRules = {};
     const enabledGlobals = Object.create(null);
     const exportedVariables = {};
@@ -269,16 +276,29 @@ function getDirectiveComments(filename, ast, ruleMapper) {
 
     ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
         const trimmedCommentText = comment.value.trim();
-        const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/u.exec(trimmedCommentText);
+        const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText);
 
         if (!match) {
             return;
         }
+        const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(match[1]);
+
+        if (warnInlineConfig && (lineCommentSupported || comment.type === "Block")) {
+            const kind = comment.type === "Block" ? `/*${match[1]}*/` : `//${match[1]}`;
+
+            problems.push(createLintingProblem({
+                ruleId: null,
+                message: `'${kind}' has no effect because you have 'noInlineConfig' setting in ${warnInlineConfig}.`,
+                loc: comment.loc,
+                severity: 1
+            }));
+            return;
+        }
 
         const directiveValue = trimmedCommentText.slice(match.index + match[1].length);
         let directiveType = "";
 
-        if (/^eslint-disable-(next-)?line$/u.test(match[1])) {
+        if (lineCommentSupported) {
             if (comment.loc.start.line === comment.loc.end.line) {
                 directiveType = match[1].slice("eslint-".length);
             } else {
@@ -441,16 +461,27 @@ function normalizeFilename(filename) {
     return index === -1 ? filename : parts.slice(index).join(path.sep);
 }
 
+// eslint-disable-next-line valid-jsdoc
 /**
  * Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
  * consistent shape.
  * @param {VerifyOptions} providedOptions Options
- * @returns {Required<VerifyOptions>} Normalized options
+ * @param {ConfigData} config Config.
+ * @returns {Required<VerifyOptions> & { warnInlineConfig: string|null }} Normalized options
  */
-function normalizeVerifyOptions(providedOptions) {
+function normalizeVerifyOptions(providedOptions, config) {
+    const disableInlineConfig = config.noInlineConfig === true;
+    const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
+    const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
+        ? ` (${config.configNameOfNoInlineConfig})`
+        : "";
+
     return {
         filename: normalizeFilename(providedOptions.filename || "<input>"),
-        allowInlineConfig: providedOptions.allowInlineConfig !== false,
+        allowInlineConfig: !ignoreInlineConfig,
+        warnInlineConfig: disableInlineConfig && !ignoreInlineConfig
+            ? `your config${configNameOfNoInlineConfig}`
+            : null,
         reportUnusedDisableDirectives: Boolean(providedOptions.reportUnusedDisableDirectives),
         disableFixes: Boolean(providedOptions.disableFixes)
     };
@@ -984,7 +1015,7 @@ class Linter {
     _verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
         const slots = internalSlotsMap.get(this);
         const config = providedConfig || {};
-        const options = normalizeVerifyOptions(providedOptions);
+        const options = normalizeVerifyOptions(providedOptions, config);
         let text;
 
         // evaluate arguments
@@ -1019,7 +1050,9 @@ class Linter {
         }
 
         // search and apply "eslint-env *".
-        const envInFile = findEslintEnv(text);
+        const envInFile = options.allowInlineConfig && !options.warnInlineConfig
+            ? findEslintEnv(text)
+            : {};
         const resolvedEnvConfig = Object.assign({ builtin: true }, config.env, envInFile);
         const enabledEnvs = Object.keys(resolvedEnvConfig)
             .filter(envName => resolvedEnvConfig[envName])
@@ -1062,7 +1095,7 @@ class Linter {
 
         const sourceCode = slots.lastSourceCode;
         const commentDirectives = options.allowInlineConfig
-            ? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId))
+            ? getDirectiveComments(options.filename, sourceCode.ast, ruleId => getRule(slots, ruleId), options.warnInlineConfig)
             : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
 
         // augment global scope with declared global variables
diff --git a/lib/rules/accessor-pairs.js b/lib/rules/accessor-pairs.js
index aca231848..9c78bdc70 100644
--- a/lib/rules/accessor-pairs.js
+++ b/lib/rules/accessor-pairs.js
@@ -5,10 +5,87 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("./utils/ast-utils");
+
+//------------------------------------------------------------------------------
+// Typedefs
+//------------------------------------------------------------------------------
+
+/**
+ * Property name if it can be computed statically, otherwise the list of the tokens of the key node.
+ * @typedef {string|Token[]} Key
+ */
+
+/**
+ * Accessor nodes with the same key.
+ * @typedef {Object} AccessorData
+ * @property {Key} key Accessor's key
+ * @property {ASTNode[]} getters List of getter nodes.
+ * @property {ASTNode[]} setters List of setter nodes.
+ */
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Checks whether or not the given lists represent the equal tokens in the same order.
+ * Tokens are compared by their properties, not by instance.
+ * @param {Token[]} left First list of tokens.
+ * @param {Token[]} right Second list of tokens.
+ * @returns {boolean} `true` if the lists have same tokens.
+ */
+function areEqualTokenLists(left, right) {
+    if (left.length !== right.length) {
+        return false;
+    }
+
+    for (let i = 0; i < left.length; i++) {
+        const leftToken = left[i],
+            rightToken = right[i];
+
+        if (leftToken.type !== rightToken.type || leftToken.value !== rightToken.value) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/**
+ * Checks whether or not the given keys are equal.
+ * @param {Key} left First key.
+ * @param {Key} right Second key.
+ * @returns {boolean} `true` if the keys are equal.
+ */
+function areEqualKeys(left, right) {
+    if (typeof left === "string" && typeof right === "string") {
+
+        // Statically computed names.
+        return left === right;
+    }
+    if (Array.isArray(left) && Array.isArray(right)) {
+
+        // Token lists.
+        return areEqualTokenLists(left, right);
+    }
+
+    return false;
+}
+
+/**
+ * Checks whether or not a given node is of an accessor kind ('get' or 'set').
+ * @param {ASTNode} node - A node to check.
+ * @returns {boolean} `true` if the node is of an accessor kind.
+ */
+function isAccessorKind(node) {
+    return node.kind === "get" || node.kind === "set";
+}
+
 /**
  * Checks whether or not a given node is an `Identifier` node which was named a given name.
  * @param {ASTNode} node - A node to check.
@@ -97,69 +174,152 @@ module.exports = {
         }],
 
         messages: {
-            getter: "Getter is not present.",
-            setter: "Setter is not present."
+            missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.",
+            missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.",
+            missingGetterInObjectLiteral: "Getter is not present for {{ name }}.",
+            missingSetterInObjectLiteral: "Setter is not present for {{ name }}."
         }
     },
     create(context) {
         const config = context.options[0] || {};
         const checkGetWithoutSet = config.getWithoutSet === true;
         const checkSetWithoutGet = config.setWithoutGet !== false;
+        const sourceCode = context.getSourceCode();
 
         /**
-         * Checks a object expression to see if it has setter and getter both present or none.
-         * @param {ASTNode} node The node to check.
+         * Reports the given node.
+         * @param {ASTNode} node The node to report.
+         * @param {string} messageKind "missingGetter" or "missingSetter".
          * @returns {void}
          * @private
          */
-        function checkLonelySetGet(node) {
-            let isSetPresent = false;
-            let isGetPresent = false;
-            const isDescriptor = isPropertyDescriptor(node);
+        function report(node, messageKind) {
+            if (node.type === "Property") {
+                context.report({
+                    node,
+                    messageId: `${messageKind}InObjectLiteral`,
+                    loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
+                    data: { name: astUtils.getFunctionNameWithKind(node.value) }
+                });
+            } else {
+                context.report({
+                    node,
+                    messageId: `${messageKind}InPropertyDescriptor`
+                });
+            }
+        }
 
-            for (let i = 0, end = node.properties.length; i < end; i++) {
-                const property = node.properties[i];
+        /**
+         * Reports each of the nodes in the given list using the same messageId.
+         * @param {ASTNode[]} nodes Nodes to report.
+         * @param {string} messageKind "missingGetter" or "missingSetter".
+         * @returns {void}
+         * @private
+         */
+        function reportList(nodes, messageKind) {
+            for (const node of nodes) {
+                report(node, messageKind);
+            }
+        }
 
-                let propToCheck = "";
+        /**
+         * Creates a new `AccessorData` object for the given getter or setter node.
+         * @param {ASTNode} node A getter or setter node.
+         * @returns {AccessorData} New `AccessorData` object that contains the given node.
+         * @private
+         */
+        function createAccessorData(node) {
+            const name = astUtils.getStaticPropertyName(node);
+            const key = (name !== null) ? name : sourceCode.getTokens(node.key);
 
-                if (property.kind === "init") {
-                    if (isDescriptor && !property.computed) {
-                        propToCheck = property.key.name;
-                    }
-                } else {
-                    propToCheck = property.kind;
-                }
+            return {
+                key,
+                getters: node.kind === "get" ? [node] : [],
+                setters: node.kind === "set" ? [node] : []
+            };
+        }
 
-                switch (propToCheck) {
-                    case "set":
-                        isSetPresent = true;
-                        break;
+        /**
+         * Merges the given `AccessorData` object into the given accessors list.
+         * @param {AccessorData[]} accessors The list to merge into.
+         * @param {AccessorData} accessorData The object to merge.
+         * @returns {AccessorData[]} The same instance with the merged object.
+         * @private
+         */
+        function mergeAccessorData(accessors, accessorData) {
+            const equalKeyElement = accessors.find(a => areEqualKeys(a.key, accessorData.key));
 
-                    case "get":
-                        isGetPresent = true;
-                        break;
+            if (equalKeyElement) {
+                equalKeyElement.getters.push(...accessorData.getters);
+                equalKeyElement.setters.push(...accessorData.setters);
+            } else {
+                accessors.push(accessorData);
+            }
 
-                    default:
+            return accessors;
+        }
 
-                        // Do nothing
-                }
+        /**
+         * Checks accessor pairs in the given list of nodes.
+         * @param {ASTNode[]} nodes The list to check.
+         * @returns {void}
+         * @private
+         */
+        function checkList(nodes) {
+            const accessors = nodes
+                .filter(isAccessorKind)
+                .map(createAccessorData)
+                .reduce(mergeAccessorData, []);
 
-                if (isSetPresent && isGetPresent) {
-                    break;
+            for (const { getters, setters } of accessors) {
+                if (checkSetWithoutGet && setters.length && !getters.length) {
+                    reportList(setters, "missingGetter");
+                }
+                if (checkGetWithoutSet && getters.length && !setters.length) {
+                    reportList(getters, "missingSetter");
                 }
             }
+        }
 
-            if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
-                context.report({ node, messageId: "getter" });
-            } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
-                context.report({ node, messageId: "setter" });
+        /**
+         * Checks accessor pairs in an object literal.
+         * @param {ASTNode} node `ObjectExpression` node to check.
+         * @returns {void}
+         * @private
+         */
+        function checkObjectLiteral(node) {
+            checkList(node.properties.filter(p => p.type === "Property"));
+        }
+
+        /**
+         * Checks accessor pairs in a property descriptor.
+         * @param {ASTNode} node Property descriptor `ObjectExpression` node to check.
+         * @returns {void}
+         * @private
+         */
+        function checkPropertyDescriptor(node) {
+            const namesToCheck = node.properties
+                .filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
+                .map(({ key }) => key.name);
+
+            const hasGetter = namesToCheck.includes("get");
+            const hasSetter = namesToCheck.includes("set");
+
+            if (checkSetWithoutGet && hasSetter && !hasGetter) {
+                report(node, "missingGetter");
+            }
+            if (checkGetWithoutSet && hasGetter && !hasSetter) {
+                report(node, "missingSetter");
             }
         }
 
         return {
             ObjectExpression(node) {
                 if (checkSetWithoutGet || checkGetWithoutSet) {
-                    checkLonelySetGet(node);
+                    checkObjectLiteral(node);
+                    if (isPropertyDescriptor(node)) {
+                        checkPropertyDescriptor(node);
+                    }
                 }
             }
         };
diff --git a/lib/rules/class-methods-use-this.js b/lib/rules/class-methods-use-this.js
index c15f32e66..4bf17090a 100644
--- a/lib/rules/class-methods-use-this.js
+++ b/lib/rules/class-methods-use-this.js
@@ -5,6 +5,12 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("./utils/ast-utils");
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -34,7 +40,7 @@ module.exports = {
         }],
 
         messages: {
-            missingThis: "Expected 'this' to be used by class method '{{name}}'."
+            missingThis: "Expected 'this' to be used by class {{name}}."
         }
     },
     create(context) {
@@ -90,7 +96,7 @@ module.exports = {
                     node,
                     messageId: "missingThis",
                     data: {
-                        name: node.parent.key.name
+                        name: astUtils.getFunctionNameWithKind(node)
                     }
                 });
             }
diff --git a/lib/rules/dot-notation.js b/lib/rules/dot-notation.js
index 61184ddcd..2e8fff8b9 100644
--- a/lib/rules/dot-notation.js
+++ b/lib/rules/dot-notation.js
@@ -9,13 +9,16 @@
 //------------------------------------------------------------------------------
 
 const astUtils = require("./utils/ast-utils");
+const keywords = require("./utils/keywords");
 
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
 
 const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
-const keywords = require("./utils/keywords");
+
+// `null` literal must be handled separately.
+const literalTypesToCheck = new Set(["string", "boolean"]);
 
 module.exports = {
     meta: {
@@ -115,7 +118,8 @@ module.exports = {
             MemberExpression(node) {
                 if (
                     node.computed &&
-                    node.property.type === "Literal"
+                    node.property.type === "Literal" &&
+                    (literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property))
                 ) {
                     checkComputedProperty(node, node.property.value);
                 }
diff --git a/lib/rules/function-call-argument-newline.js b/lib/rules/function-call-argument-newline.js
new file mode 100644
index 000000000..8bf31f7c7
--- /dev/null
+++ b/lib/rules/function-call-argument-newline.js
@@ -0,0 +1,120 @@
+/**
+ * @fileoverview Rule to enforce line breaks between arguments of a function call
+ * @author Alexey Gonchar <https://github.com/finico>
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "layout",
+
+        docs: {
+            description: "enforce line breaks between arguments of a function call",
+            category: "Stylistic Issues",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/function-call-argument-newline"
+        },
+
+        fixable: "whitespace",
+
+        schema: [
+            {
+                enum: ["always", "never", "consistent"]
+            }
+        ],
+
+        messages: {
+            unexpectedLineBreak: "There should be no line break here.",
+            missingLineBreak: "There should be a line break after this argument."
+        }
+    },
+
+    create(context) {
+        const sourceCode = context.getSourceCode();
+
+        const checkers = {
+            unexpected: {
+                messageId: "unexpectedLineBreak",
+                check: (prevToken, currentToken) => prevToken.loc.start.line !== currentToken.loc.start.line,
+                createFix: (token, tokenBefore) => fixer =>
+                    fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], " ")
+            },
+            missing: {
+                messageId: "missingLineBreak",
+                check: (prevToken, currentToken) => prevToken.loc.start.line === currentToken.loc.start.line,
+                createFix: (token, tokenBefore) => fixer =>
+                    fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], "\n")
+            }
+        };
+
+        /**
+         * Check all arguments for line breaks in the CallExpression
+         * @param {CallExpression} node node to evaluate
+         * @param {{ messageId: string, check: Function }} checker selected checker
+         * @returns {void}
+         * @private
+         */
+        function checkArguments(node, checker) {
+            for (let i = 1; i < node.arguments.length; i++) {
+                const prevArgToken = sourceCode.getFirstToken(node.arguments[i - 1]);
+                const currentArgToken = sourceCode.getFirstToken(node.arguments[i]);
+
+                if (checker.check(prevArgToken, currentArgToken)) {
+                    const tokenBefore = sourceCode.getTokenBefore(
+                        currentArgToken,
+                        { includeComments: true }
+                    );
+
+                    context.report({
+                        node,
+                        loc: {
+                            start: tokenBefore.loc.end,
+                            end: currentArgToken.loc.start
+                        },
+                        messageId: checker.messageId,
+                        fix: checker.createFix(currentArgToken, tokenBefore)
+                    });
+                }
+            }
+        }
+
+        /**
+         * Check if open space is present in a function name
+         * @param {CallExpression} node node to evaluate
+         * @returns {void}
+         * @private
+         */
+        function check(node) {
+            if (node.arguments.length < 2) {
+                return;
+            }
+
+            const option = context.options[0] || "always";
+
+            if (option === "never") {
+                checkArguments(node, checkers.unexpected);
+            } else if (option === "always") {
+                checkArguments(node, checkers.missing);
+            } else if (option === "consistent") {
+                const firstArgToken = sourceCode.getFirstToken(node.arguments[0]);
+                const secondArgToken = sourceCode.getFirstToken(node.arguments[1]);
+
+                if (firstArgToken.loc.start.line === secondArgToken.loc.start.line) {
+                    checkArguments(node, checkers.unexpected);
+                } else {
+                    checkArguments(node, checkers.missing);
+                }
+            }
+        }
+
+        return {
+            CallExpression: check,
+            NewExpression: check
+        };
+    }
+};
diff --git a/lib/rules/index.js b/lib/rules/index.js
index 45045904b..c42ae41d6 100644
--- a/lib/rules/index.js
+++ b/lib/rules/index.js
@@ -46,6 +46,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
     "func-name-matching": () => require("./func-name-matching"),
     "func-names": () => require("./func-names"),
     "func-style": () => require("./func-style"),
+    "function-call-argument-newline": () => require("./function-call-argument-newline"),
     "function-paren-newline": () => require("./function-paren-newline"),
     "generator-star-spacing": () => require("./generator-star-spacing"),
     "getter-return": () => require("./getter-return"),
diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js
index d0751b4a2..1b7f69cfa 100644
--- a/lib/rules/no-dupe-keys.js
+++ b/lib/rules/no-dupe-keys.js
@@ -120,7 +120,7 @@ module.exports = {
                 }
 
                 // Skip if the name is not static.
-                if (!name) {
+                if (name === null) {
                     return;
                 }
 
diff --git a/lib/rules/no-duplicate-case.js b/lib/rules/no-duplicate-case.js
index 93c8548f9..c8a0fa9da 100644
--- a/lib/rules/no-duplicate-case.js
+++ b/lib/rules/no-duplicate-case.js
@@ -33,17 +33,19 @@ module.exports = {
 
         return {
             SwitchStatement(node) {
-                const mapping = {};
+                const previousKeys = new Set();
 
-                node.cases.forEach(switchCase => {
-                    const key = sourceCode.getText(switchCase.test);
+                for (const switchCase of node.cases) {
+                    if (switchCase.test) {
+                        const key = sourceCode.getText(switchCase.test);
 
-                    if (mapping[key]) {
-                        context.report({ node: switchCase, messageId: "unexpected" });
-                    } else {
-                        mapping[key] = switchCase;
+                        if (previousKeys.has(key)) {
+                            context.report({ node: switchCase, messageId: "unexpected" });
+                        } else {
+                            previousKeys.add(key);
+                        }
                     }
-                });
+                }
             }
         };
     }
diff --git a/lib/rules/no-extra-bind.js b/lib/rules/no-extra-bind.js
index 5380cf217..cc0b1f843 100644
--- a/lib/rules/no-extra-bind.js
+++ b/lib/rules/no-extra-bind.js
@@ -98,6 +98,7 @@ module.exports = {
                 grandparent.type === "CallExpression" &&
                 grandparent.callee === parent &&
                 grandparent.arguments.length === 1 &&
+                grandparent.arguments[0].type !== "SpreadElement" &&
                 parent.type === "MemberExpression" &&
                 parent.object === node &&
                 astUtils.getStaticPropertyName(parent) === "bind"
diff --git a/lib/rules/no-extra-boolean-cast.js b/lib/rules/no-extra-boolean-cast.js
index 8dd526477..9ae9b5be6 100644
--- a/lib/rules/no-extra-boolean-cast.js
+++ b/lib/rules/no-extra-boolean-cast.js
@@ -50,8 +50,8 @@ module.exports = {
         /**
          * Check if a node is in a context where its value would be coerced to a boolean at runtime.
          *
-         * @param {Object} node The node
-         * @param {Object} parent Its parent
+         * @param {ASTNode} node The node
+         * @param {ASTNode} parent Its parent
          * @returns {boolean} If it is in a boolean context
          */
         function isInBooleanContext(node, parent) {
@@ -65,6 +65,15 @@ module.exports = {
             );
         }
 
+        /**
+         * Check if a node has comments inside.
+         *
+         * @param {ASTNode} node The node to check.
+         * @returns {boolean} `true` if it has comments inside.
+         */
+        function hasCommentsInside(node) {
+            return Boolean(sourceCode.getCommentsInside(node).length);
+        }
 
         return {
             UnaryExpression(node) {
@@ -89,7 +98,12 @@ module.exports = {
                     context.report({
                         node,
                         messageId: "unexpectedNegation",
-                        fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument))
+                        fix: fixer => {
+                            if (hasCommentsInside(parent)) {
+                                return null;
+                            }
+                            return fixer.replaceText(parent, sourceCode.getText(node.argument));
+                        }
                     });
                 }
             },
@@ -106,10 +120,35 @@ module.exports = {
                         messageId: "unexpectedCall",
                         fix: fixer => {
                             if (!node.arguments.length) {
-                                return fixer.replaceText(parent, "true");
+                                if (parent.type === "UnaryExpression" && parent.operator === "!") {
+
+                                    // !Boolean() -> true
+
+                                    if (hasCommentsInside(parent)) {
+                                        return null;
+                                    }
+
+                                    const replacement = "true";
+                                    let prefix = "";
+                                    const tokenBefore = sourceCode.getTokenBefore(parent);
+
+                                    if (tokenBefore && tokenBefore.range[1] === parent.range[0] &&
+                                            !astUtils.canTokensBeAdjacent(tokenBefore, replacement)) {
+                                        prefix = " ";
+                                    }
+
+                                    return fixer.replaceText(parent, prefix + replacement);
+                                }
+
+                                // Boolean() -> false
+                                if (hasCommentsInside(node)) {
+                                    return null;
+                                }
+                                return fixer.replaceText(node, "false");
                             }
 
-                            if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement") {
+                            if (node.arguments.length > 1 || node.arguments[0].type === "SpreadElement" ||
+                                    hasCommentsInside(node)) {
                                 return null;
                             }
 
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index c9278f2d0..5e41d7468 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -980,7 +980,21 @@ module.exports = {
 
             SpreadElement: checkSpreadOperator,
             SpreadProperty: checkSpreadOperator,
-            ExperimentalSpreadProperty: checkSpreadOperator
+            ExperimentalSpreadProperty: checkSpreadOperator,
+
+            TemplateLiteral(node) {
+                node.expressions
+                    .filter(e => e && hasExcessParens(e))
+                    .forEach(report);
+            },
+
+            AssignmentPattern(node) {
+                const { right } = node;
+
+                if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
+                    report(right);
+                }
+            }
         };
 
     }
diff --git a/lib/rules/no-mixed-operators.js b/lib/rules/no-mixed-operators.js
index 21e1d95c6..8d1c7a6af 100644
--- a/lib/rules/no-mixed-operators.js
+++ b/lib/rules/no-mixed-operators.js
@@ -20,12 +20,14 @@ const BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"];
 const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="];
 const LOGICAL_OPERATORS = ["&&", "||"];
 const RELATIONAL_OPERATORS = ["in", "instanceof"];
+const TERNARY_OPERATOR = ["?:"];
 const ALL_OPERATORS = [].concat(
     ARITHMETIC_OPERATORS,
     BITWISE_OPERATORS,
     COMPARISON_OPERATORS,
     LOGICAL_OPERATORS,
-    RELATIONAL_OPERATORS
+    RELATIONAL_OPERATORS,
+    TERNARY_OPERATOR
 );
 const DEFAULT_GROUPS = [
     ARITHMETIC_OPERATORS,
@@ -34,7 +36,7 @@ const DEFAULT_GROUPS = [
     LOGICAL_OPERATORS,
     RELATIONAL_OPERATORS
 ];
-const TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/u;
+const TARGET_NODE_TYPE = /^(?:Binary|Logical|Conditional)Expression$/u;
 
 /**
  * Normalizes options.
@@ -65,6 +67,18 @@ function includesBothInAGroup(groups, left, right) {
     return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1);
 }
 
+/**
+ * Checks whether the given node is a conditional expression and returns the test node else the left node.
+ *
+ * @param {ASTNode} node - A node which can be a BinaryExpression or a LogicalExpression node.
+ * This parent node can be BinaryExpression, LogicalExpression
+ *      , or a ConditionalExpression node
+ * @returns {ASTNode} node the appropriate node(left or test).
+ */
+function getChildNode(node) {
+    return node.type === "ConditionalExpression" ? node.test : node.left;
+}
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -121,7 +135,7 @@ module.exports = {
             const b = node.parent;
 
             return (
-                !includesBothInAGroup(options.groups, a.operator, b.operator) ||
+                !includesBothInAGroup(options.groups, a.operator, b.type === "ConditionalExpression" ? "?:" : b.operator) ||
                 (
                     options.allowSamePrecedence &&
                     astUtils.getPrecedence(a) === astUtils.getPrecedence(b)
@@ -139,12 +153,25 @@ module.exports = {
          * @returns {boolean} `true` if the node was mixed.
          */
         function isMixedWithParent(node) {
+
             return (
                 node.operator !== node.parent.operator &&
                 !astUtils.isParenthesised(sourceCode, node)
             );
         }
 
+        /**
+         * Checks whether the operator of a given node is mixed with a
+         * conditional expression.
+         *
+         * @param {ASTNode} node - A node to check. This is a conditional
+         *      expression node
+         * @returns {boolean} `true` if the node was mixed.
+         */
+        function isMixedWithConditionalParent(node) {
+            return !astUtils.isParenthesised(sourceCode, node) && !astUtils.isParenthesised(sourceCode, node.test);
+        }
+
         /**
          * Gets the operator token of a given node.
          *
@@ -153,7 +180,7 @@ module.exports = {
          * @returns {Token} The operator token of the node.
          */
         function getOperatorToken(node) {
-            return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
+            return sourceCode.getTokenAfter(getChildNode(node), astUtils.isNotClosingParenToken);
         }
 
         /**
@@ -167,13 +194,13 @@ module.exports = {
          */
         function reportBothOperators(node) {
             const parent = node.parent;
-            const left = (parent.left === node) ? node : parent;
-            const right = (parent.left !== node) ? node : parent;
+            const left = (getChildNode(parent) === node) ? node : parent;
+            const right = (getChildNode(parent) !== node) ? node : parent;
             const message =
                 "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'.";
             const data = {
-                leftOperator: left.operator,
-                rightOperator: right.operator
+                leftOperator: left.operator || "?:",
+                rightOperator: right.operator || "?:"
             };
 
             context.report({
@@ -198,17 +225,25 @@ module.exports = {
          * @returns {void}
          */
         function check(node) {
-            if (TARGET_NODE_TYPE.test(node.parent.type) &&
-                isMixedWithParent(node) &&
-                !shouldIgnore(node)
-            ) {
-                reportBothOperators(node);
+            if (TARGET_NODE_TYPE.test(node.parent.type)) {
+                if (node.parent.type === "ConditionalExpression" && !shouldIgnore(node) && isMixedWithConditionalParent(node.parent)) {
+                    reportBothOperators(node);
+                } else {
+                    if (TARGET_NODE_TYPE.test(node.parent.type) &&
+                        isMixedWithParent(node) &&
+                        !shouldIgnore(node)
+                    ) {
+                        reportBothOperators(node);
+                    }
+                }
             }
+
         }
 
         return {
             BinaryExpression: check,
             LogicalExpression: check
+
         };
     }
 };
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 48df3aa3c..8094de57c 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -507,7 +507,7 @@ module.exports = {
             const childScopes = scope.childScopes;
             let i, l;
 
-            if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) {
+            if (scope.type !== "global" || config.vars === "all") {
                 for (i = 0, l = variables.length; i < l; ++i) {
                     const variable = variables[i];
 
diff --git a/lib/rules/prefer-template.js b/lib/rules/prefer-template.js
index f73ac34f8..a2507d452 100644
--- a/lib/rules/prefer-template.js
+++ b/lib/rules/prefer-template.js
@@ -52,16 +52,7 @@ function isOctalEscapeSequence(node) {
         return false;
     }
 
-    const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7]{1,3})/u);
-
-    if (match) {
-
-        // \0 is actually not considered an octal
-        if (match[2] !== "0" || typeof match[3] !== "undefined") {
-            return true;
-        }
-    }
-    return false;
+    return astUtils.hasOctalEscapeSequence(node.raw);
 }
 
 /**
diff --git a/lib/rules/sort-keys.js b/lib/rules/sort-keys.js
index beda42f1e..c314d4a63 100644
--- a/lib/rules/sort-keys.js
+++ b/lib/rules/sort-keys.js
@@ -29,7 +29,13 @@ const astUtils = require("./utils/ast-utils"),
  * @private
  */
 function getPropertyName(node) {
-    return astUtils.getStaticPropertyName(node) || node.key.name || null;
+    const staticName = astUtils.getStaticPropertyName(node);
+
+    if (staticName !== null) {
+        return staticName;
+    }
+
+    return node.key.name || null;
 }
 
 /**
@@ -151,9 +157,11 @@ module.exports = {
                 const numKeys = stack.numKeys;
                 const thisName = getPropertyName(node);
 
-                stack.prevName = thisName || prevName;
+                if (thisName !== null) {
+                    stack.prevName = thisName;
+                }
 
-                if (!prevName || !thisName || numKeys < minKeys) {
+                if (prevName === null || thisName === null || numKeys < minKeys) {
                     return;
                 }
 
diff --git a/lib/rules/utils/ast-utils.js b/lib/rules/utils/ast-utils.js
index 78ae7bc01..7c17fc2ec 100644
--- a/lib/rules/utils/ast-utils.js
+++ b/lib/rules/utils/ast-utils.js
@@ -38,6 +38,7 @@ const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
 const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
 
 const DECIMAL_INTEGER_PATTERN = /^(0|[1-9]\d*)$/u;
+const OCTAL_ESCAPE_PATTERN = /^(?:[^\\]|\\[^0-7]|\\0(?![0-9]))*\\(?:[1-7]|0[0-9])/u;
 
 /**
  * Checks reference if is non initializer and writable.
@@ -1101,7 +1102,7 @@ module.exports = {
         } else {
             const name = module.exports.getStaticPropertyName(parent);
 
-            if (name) {
+            if (name !== null) {
                 tokens.push(`'${name}'`);
             }
         }
@@ -1373,5 +1374,20 @@ module.exports = {
             "/*".length +
             (match ? match.index + 1 : 0)
         );
+    },
+
+    /**
+     * Determines whether the given raw string contains an octal escape sequence.
+     *
+     * "\1", "\2" ... "\7"
+     * "\00", "\01" ... "\09"
+     *
+     * "\0", when not followed by a digit, is not an octal escape sequence.
+     *
+     * @param {string} rawString A string in its raw representation.
+     * @returns {boolean} `true` if the string contains at least one octal escape sequence.
+     */
+    hasOctalEscapeSequence(rawString) {
+        return OCTAL_ESCAPE_PATTERN.test(rawString);
     }
 };
diff --git a/lib/rules/yoda.js b/lib/rules/yoda.js
index 43783c193..89c4a8afd 100644
--- a/lib/rules/yoda.js
+++ b/lib/rules/yoda.js
@@ -119,7 +119,7 @@ function same(a, b) {
             const nameA = astUtils.getStaticPropertyName(a);
 
             // x.y = x["y"]
-            if (nameA) {
+            if (nameA !== null) {
                 return (
                     same(a.object, b.object) &&
                     nameA === astUtils.getStaticPropertyName(b)
diff --git a/lib/shared/types.js b/lib/shared/types.js
index d83577999..8a889d21d 100644
--- a/lib/shared/types.js
+++ b/lib/shared/types.js
@@ -30,6 +30,7 @@ module.exports = {};
  * @property {Record<string, boolean>} [env] The environment settings.
  * @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
  * @property {Record<string, GlobalConf>} [globals] The global variable settings.
+ * @property {boolean} [noInlineConfig] The flag that disables directive comments.
  * @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
  * @property {string} [parser] The path to a parser or the package name of a parser.
  * @property {ParserOptions} [parserOptions] The parser options.
@@ -47,6 +48,7 @@ module.exports = {};
  * @property {string | string[]} [extends] The path to other config files or the package name of shareable configs.
  * @property {string | string[]} files The glob pattarns for target files.
  * @property {Record<string, GlobalConf>} [globals] The global variable settings.
+ * @property {boolean} [noInlineConfig] The flag that disables directive comments.
  * @property {OverrideConfigData[]} [overrides] The override settings per kind of files.
  * @property {string} [parser] The path to a parser or the package name of a parser.
  * @property {ParserOptions} [parserOptions] The parser options.
diff --git a/tools/rule-types.json b/tools/rule-types.json
index 1239e5f3f..eef001a20 100644
--- a/tools/rule-types.json
+++ b/tools/rule-types.json
@@ -33,6 +33,7 @@
     "func-name-matching": "suggestion",
     "func-names": "suggestion",
     "func-style": "suggestion",
+    "function-call-argument-newline": "layout",
     "function-paren-newline": "layout",
     "generator-star-spacing": "layout",
     "getter-return": "problem",


Test patch:
diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js
index 427181aff..dc42cfa68 100644
--- a/tests/lib/cli-engine/cli-engine.js
+++ b/tests/lib/cli-engine/cli-engine.js
@@ -3495,6 +3495,45 @@ describe("CLIEngine", () => {
                 assert.deepStrictEqual(filenames, ["a.js", "b.js"]);
             });
         });
+
+        describe("with 'noInlineConfig' setting", () => {
+            const root = getFixturePath("cli-engine/noInlineConfig");
+
+            it("should warn directive comments if 'noInlineConfig' was given.", () => {
+                CLIEngine = defineCLIEngineWithInMemoryFileSystem({
+                    cwd: () => root,
+                    files: {
+                        "test.js": "/* globals foo */",
+                        ".eslintrc.yml": "noInlineConfig: true"
+                    }
+                }).CLIEngine;
+                engine = new CLIEngine();
+
+                const { results } = engine.executeOnFiles(["test.js"]);
+                const messages = results[0].messages;
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].message, "'/*globals*/' has no effect because you have 'noInlineConfig' setting in your config (.eslintrc.yml).");
+            });
+
+            it("should show the config file what the 'noInlineConfig' came from.", () => {
+                CLIEngine = defineCLIEngineWithInMemoryFileSystem({
+                    cwd: () => root,
+                    files: {
+                        "node_modules/eslint-config-foo/index.js": "module.exports = {noInlineConfig: true}",
+                        "test.js": "/* globals foo */",
+                        ".eslintrc.yml": "extends: foo"
+                    }
+                }).CLIEngine;
+                engine = new CLIEngine();
+
+                const { results } = engine.executeOnFiles(["test.js"]);
+                const messages = results[0].messages;
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].message, "'/*globals*/' has no effect because you have 'noInlineConfig' setting in your config (.eslintrc.yml » eslint-config-foo).");
+            });
+        });
     });
 
     describe("getConfigForFile", () => {
diff --git a/tests/lib/cli-engine/config-array-factory.js b/tests/lib/cli-engine/config-array-factory.js
index fe5f9de84..b9f404dca 100644
--- a/tests/lib/cli-engine/config-array-factory.js
+++ b/tests/lib/cli-engine/config-array-factory.js
@@ -30,6 +30,7 @@ function assertConfigArrayElement(actual, providedExpected) {
         criteria: null,
         env: void 0,
         globals: void 0,
+        noInlineConfig: void 0,
         parser: void 0,
         parserOptions: void 0,
         plugins: void 0,
@@ -53,6 +54,7 @@ function assertConfig(actual, providedExpected) {
     const expected = {
         env: {},
         globals: {},
+        noInlineConfig: void 0,
         parser: null,
         parserOptions: {},
         plugins: [],
diff --git a/tests/lib/cli-engine/config-array/config-array.js b/tests/lib/cli-engine/config-array/config-array.js
index 07cf0f2c6..82f3e7507 100644
--- a/tests/lib/cli-engine/config-array/config-array.js
+++ b/tests/lib/cli-engine/config-array/config-array.js
@@ -423,8 +423,10 @@ describe("ConfigArray", () => {
             const result = merge(config[0], config[1]);
 
             assert.deepStrictEqual(result, {
+                configNameOfNoInlineConfig: "",
                 env: {},
                 globals: {},
+                noInlineConfig: void 0,
                 parser: null,
                 parserOptions: {
                     ecmaFeatures: {
@@ -452,8 +454,10 @@ describe("ConfigArray", () => {
             const result = merge(config[0], config[1]);
 
             assert.deepStrictEqual(result, {
+                configNameOfNoInlineConfig: "",
                 env: {},
                 globals: {},
+                noInlineConfig: void 0,
                 parser: null,
                 parserOptions: {
                     ecmaFeatures: {
@@ -565,6 +569,7 @@ describe("ConfigArray", () => {
             const result = merge(config[0], config[1]);
 
             assert.deepStrictEqual(result, {
+                configNameOfNoInlineConfig: "",
                 parser: null,
                 parserOptions: {
                     ecmaFeatures: {
@@ -601,7 +606,8 @@ describe("ConfigArray", () => {
                     "valid-jsdoc": [2]
                 },
                 settings: {},
-                processor: null
+                processor: null,
+                noInlineConfig: void 0
             });
             assert.deepStrictEqual(config[0], {
                 rules: {
diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js
index 3cfef3bbe..b1b621935 100644
--- a/tests/lib/linter/linter.js
+++ b/tests/lib/linter/linter.js
@@ -74,7 +74,7 @@ const ESLINT_ENV = "eslint-env";
 describe("Linter", () => {
     const filename = "filename.js";
 
-    /** @type {InstanceType<import("../../lib/linter.js")["Linter"]>} */
+    /** @type {InstanceType<import("../../../lib/linter/linter.js")["Linter"]>} */
     let linter;
 
     beforeEach(() => {
@@ -3134,37 +3134,64 @@ describe("Linter", () => {
 
         it("should report a violation for env changes", () => {
             const code = [
-                `/*${ESLINT_ENV} browser*/`
+                `/*${ESLINT_ENV} browser*/ window`
             ].join("\n");
             const config = {
                 rules: {
-                    test: 2
+                    "no-undef": 2
                 }
             };
-            let ok = false;
+            const messages = linter.verify(code, config, { allowInlineConfig: false });
 
-            linter.defineRules({
-                test(context) {
-                    return {
-                        Program() {
-                            const scope = context.getScope();
-                            const sourceCode = context.getSourceCode();
-                            const comments = sourceCode.getAllComments();
-
-                            assert.strictEqual(1, comments.length);
-
-                            const windowVar = getVariable(scope, "window");
+            assert.strictEqual(messages.length, 1);
+            assert.strictEqual(messages[0].ruleId, "no-undef");
+        });
+    });
 
-                            assert.notOk(windowVar.eslintExplicitGlobal);
+    describe("when evaluating code with 'noInlineComment'", () => {
+        for (const directive of [
+            "globals foo",
+            "global foo",
+            "exported foo",
+            "eslint eqeqeq: error",
+            "eslint-disable eqeqeq",
+            "eslint-disable-line eqeqeq",
+            "eslint-disable-next-line eqeqeq",
+            "eslint-enable eqeqeq",
+            "eslint-env es6"
+        ]) {
+            // eslint-disable-next-line no-loop-func
+            it(`should warn '/* ${directive} */' if 'noInlineConfig' was given.`, () => {
+                const messages = linter.verify(`/* ${directive} */`, { noInlineConfig: true });
+
+                assert.deepStrictEqual(messages.length, 1);
+                assert.deepStrictEqual(messages[0].fatal, void 0);
+                assert.deepStrictEqual(messages[0].ruleId, null);
+                assert.deepStrictEqual(messages[0].severity, 1);
+                assert.deepStrictEqual(messages[0].message, `'/*${directive.split(" ")[0]}*/' has no effect because you have 'noInlineConfig' setting in your config.`);
+            });
+        }
 
-                            ok = true;
-                        }
-                    };
-                }
+        for (const directive of [
+            "eslint-disable-line eqeqeq",
+            "eslint-disable-next-line eqeqeq"
+        ]) {
+            // eslint-disable-next-line no-loop-func
+            it(`should warn '// ${directive}' if 'noInlineConfig' was given.`, () => {
+                const messages = linter.verify(`// ${directive}`, { noInlineConfig: true });
+
+                assert.deepStrictEqual(messages.length, 1);
+                assert.deepStrictEqual(messages[0].fatal, void 0);
+                assert.deepStrictEqual(messages[0].ruleId, null);
+                assert.deepStrictEqual(messages[0].severity, 1);
+                assert.deepStrictEqual(messages[0].message, `'//${directive.split(" ")[0]}' has no effect because you have 'noInlineConfig' setting in your config.`);
             });
+        }
 
-            linter.verify(code, config, { allowInlineConfig: false });
-            assert(ok);
+        it("should not warn if 'noInlineConfig' and '--no-inline-config' were given.", () => {
+            const messages = linter.verify("/* globals foo */", { noInlineConfig: true }, { allowInlineConfig: false });
+
+            assert.deepStrictEqual(messages.length, 0);
         });
     });
 
diff --git a/tests/lib/rules/accessor-pairs.js b/tests/lib/rules/accessor-pairs.js
index 42ca8461d..4f55cd10e 100644
--- a/tests/lib/rules/accessor-pairs.js
+++ b/tests/lib/rules/accessor-pairs.js
@@ -18,26 +18,301 @@ const rule = require("../../../lib/rules/accessor-pairs"),
 
 const ruleTester = new RuleTester();
 
-const getterError = { messageId: "getter" };
-const setterError = { messageId: "setter" };
-
 ruleTester.run("accessor-pairs", rule, {
     valid: [
-        "var o = { a: 1 };",
-        "var o = {\n get a() {\n return val; \n} \n};",
-        "var o = {\n set a(value) {\n val = value; \n},\n get a() {\n return val; \n} \n};",
-        "var o = {a: 1};\n Object.defineProperty(o, 'b', \n{set: function(value) {\n val = value; \n},\n get: function() {\n return val; \n} \n});",
+
+        //------------------------------------------------------------------------------
+        // General
+        //------------------------------------------------------------------------------
+
+        // Does not check object patterns
         {
-            code: "var expr = 'foo';  var o = { set [expr](value) { val = value; }, get [expr]() { return val; } };",
+            code: "var { get: foo } = bar; ({ set: foo } = bar);",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
             parserOptions: { ecmaVersion: 6 }
         },
         {
-            code: "var o = {\n set a(value) {\n val = value; \n} \n};",
-            options: [{
-                setWithoutGet: false
-            }]
+            code: "var { set } = foo; ({ get } = foo);",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        //------------------------------------------------------------------------------
+        // Object literals
+        //------------------------------------------------------------------------------
+
+        // Test default settings, this would be an error if `getWithoutSet` was set to `true`
+        "var o = { get a() {} }",
+
+        // No accessors
+        {
+            code: "var o = {};",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { a: 1 };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { a };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { a: get };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { a: set };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get: function(){} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { set: function(foo){} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { set };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { [get]: function() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { [set]: function(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { set(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        // Disabled options
+        {
+            code: "var o = { get a() {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: false }]
+        },
+        {
+            code: "var o = { get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: false }]
+        },
+        {
+            code: "var o = { set a(foo) {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: false }]
+        },
+        {
+            code: "var o = { set a(foo) {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { set a(foo) {} };",
+            options: [{ setWithoutGet: false }]
+        },
+
+        // Valid pairs with identifiers
+        {
+            code: "var o = { get a() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: false }]
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { set a(foo) {}, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
         },
 
+        // Valid pairs with statically computed names
+        {
+            code: "var o = { get 'a'() {}, set 'a'(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get a() {}, set 'a'(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get ['abc']() {}, set ['abc'](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [1e2]() {}, set 100(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get abc() {}, set [`abc`](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get ['123']() {}, set 123(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        // Valid pairs with expressions
+        {
+            code: "var o = { get [a]() {}, set [a](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [a]() {}, set [(a)](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [(a)]() {}, set [a](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [a]() {}, set [ a ](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [/*comment*/a/*comment*/]() {}, set [a](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [f()]() {}, set [f()](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [f(a)]() {}, set [f(a)](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [a + b]() {}, set [a + b](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get [`${a}`]() {}, set [`${a}`](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        // Multiple valid pairs in the same literal
+        {
+            code: "var o = { get a() {}, set a(foo) {}, get b() {}, set b(bar) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get a() {}, set c(foo) {}, set a(bar) {}, get b() {}, get c() {}, set b(baz) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+
+        // Valid pairs with other elements
+        {
+            code: "var o = { get a() {}, set a(foo) {}, b: bar };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }]
+        },
+        {
+            code: "var o = { get a() {}, b, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get a() {}, ...b, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 }
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {}, ...a };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 }
+        },
+
+        // Duplicate keys. This is the responsibility of no-dupe-keys, but this rule still checks is there the other accessor kind.
+        {
+            code: "var o = { get a() {}, get a() {}, set a(foo) {}, };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {}, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { set a(bar) {}, get a() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get a() {}, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: false }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { set a(foo) {}, set a(foo) {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { get a() {}, set a(foo) {}, a };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var o = { a, get a() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        /*
+         * This should be actually invalid by this rule!
+         * This code creates a property with the setter only, the getter will be ignored.
+         * It's treated as 3 attempts to define the same key, and the last wins.
+         * However, this edge case is not covered, it should be reported by no-dupe-keys anyway.
+         */
+        {
+            code: "var o = { get a() {}, a:1, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        //------------------------------------------------------------------------------
+        // Property descriptors
+        //------------------------------------------------------------------------------
+
+        "var o = {a: 1};\n Object.defineProperty(o, 'b', \n{set: function(value) {\n val = value; \n},\n get: function() {\n return val; \n} \n});",
+
         // https://github.com/eslint/eslint/issues/3262
         "var o = {set: function() {}}",
         "Object.defineProperties(obj, {set: {value: function() {}}});",
@@ -46,38 +321,494 @@ ruleTester.run("accessor-pairs", rule, {
         { code: "var o = {[set]: function() {}}", parserOptions: { ecmaVersion: 6 } },
         { code: "var set = 'value'; Object.defineProperty(obj, 'foo', {[set]: function(value) {}});", parserOptions: { ecmaVersion: 6 } }
     ],
+
     invalid: [
+
+        //------------------------------------------------------------------------------
+        // Object literals
+        //------------------------------------------------------------------------------
+
+        // Test default settings
+        {
+            code: "var o = { set a(value) {} };",
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property" }]
+        },
+
+        // Test that the options do not affect each other
+        {
+            code: "var o = { set a(value) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: false }],
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set a(value) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get a() {} };",
+            options: [{ setWithoutGet: false, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get a() {} };",
+            options: [{ getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property" }]
+        },
+
+        // Various kinds of the getter's key
+        {
+            code: "var o = { get abc() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get 'abc'() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get 123() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter '123'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get 1e2() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter '100'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get ['abc']() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get [`abc`]() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get [123]() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter '123'.", type: "Property" }]
+        },
+        {
+            code: "var o = { get [abc]() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter.", type: "Property" }]
+        },
+        {
+            code: "var o = { get [f(abc)]() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter.", type: "Property" }]
+        },
+        {
+            code: "var o = { get [a + b]() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter.", type: "Property" }]
+        },
+
+        // Various kinds of the setter's key
+        {
+            code: "var o = { set abc(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set 'abc'(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set 123(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter '123'.", type: "Property" }]
+        },
         {
-            code: "var o = {\n set a(value) {\n val = value; \n} \n};",
-            errors: [getterError]
+            code: "var o = { set 1e2(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter '100'.", type: "Property" }]
         },
         {
-            code: "var o = {\n get a() {\n return val; \n} \n};",
-            options: [{
-                getWithoutSet: true
-            }],
-            errors: [setterError]
+            code: "var o = { set ['abc'](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set [`abc`](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter 'abc'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set [123](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter '123'.", type: "Property" }]
+        },
+        {
+            code: "var o = { set [abc](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter.", type: "Property" }]
+        },
+        {
+            code: "var o = { set [f(abc)](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter.", type: "Property" }]
+        },
+        {
+            code: "var o = { set [a + b](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter.", type: "Property" }]
+        },
+
+        // Different keys
+        {
+            code: "var o = { get a() {}, set b(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'b'.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { set a(foo) {}, get b() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 11 },
+                { message: "Setter is not present for getter 'b'.", type: "Property", column: 26 }
+            ]
         },
+        {
+            code: "var o = { get 1() {}, set b(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter '1'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'b'.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { get a() {}, set 1(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter '1'.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { get a() {}, set 'a '(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'a '.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { get ' a'() {}, set 'a'(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter ' a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 26 }
+            ]
+        },
+        {
+            code: "var o = { get ''() {}, set ' '(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { messageId: "missingSetterInObjectLiteral", type: "Property", column: 11 }, // TODO: Change to message when getFunctionNameWithKind gets fixed
+                { message: "Getter is not present for setter ' '.", type: "Property", column: 24 }
+            ]
+        },
+        {
+            code: "var o = { get ''() {}, set null(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { messageId: "missingSetterInObjectLiteral", type: "Property", column: 11 }, // TODO: Change to message when getFunctionNameWithKind gets fixed
+                { message: "Getter is not present for setter 'null'.", type: "Property", column: 24 }
+            ]
+        },
+        {
+            code: "var o = { get [`a`]() {}, set b(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'b'.", type: "Property", column: 27 }
+            ]
+        },
+        {
+            code: "var o = { get [a]() {}, set [b](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter.", type: "Property", column: 25 }
+            ]
+        },
+        {
+            code: "var o = { get [a]() {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 25 }
+            ]
+        },
+        {
+            code: "var o = { get a() {}, set [a](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { get [a + b]() {}, set [a - b](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter.", type: "Property", column: 29 }
+            ]
+        },
+        {
+            code: "var o = { get [`${0} `]() {}, set [`${0}`](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter.", type: "Property", column: 31 }
+            ]
+        },
+
+        // Multiple invalid of same and different kinds
+        {
+            code: "var o = { get a() {}, get b() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Setter is not present for getter 'b'.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { set a(foo) {}, set b(bar) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'b'.", type: "Property", column: 26 }
+            ]
+        },
+        {
+            code: "var o = { get a() {}, set b(foo) {}, set c(foo) {}, get d() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'b'.", type: "Property", column: 23 },
+                { message: "Getter is not present for setter 'c'.", type: "Property", column: 38 },
+                { message: "Setter is not present for getter 'd'.", type: "Property", column: 53 }
+            ]
+        },
+
+        // Checks per object literal
+        {
+            code: "var o1 = { get a() {} }, o2 = { set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 12 },
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 33 }
+            ]
+        },
+        {
+            code: "var o1 = { set a(foo) {} }, o2 = { get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 12 },
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 36 }
+            ]
+        },
+
+        // Combinations or valid and invalid
+        {
+            code: "var o = { get a() {}, get b() {}, set b(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { get b() {}, get a() {}, set b(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 23 }]
+        },
+        {
+            code: "var o = { get b() {}, set b(foo) {}, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 38 }]
+        },
+        {
+            code: "var o = { set a(foo) {}, get b() {}, set b(bar) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { get b() {}, set a(foo) {}, set b(bar) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 23 }]
+        },
+        {
+            code: "var o = { get b() {}, set b(bar) {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 38 }]
+        },
+        {
+            code: "var o = { get v1() {}, set i1(foo) {}, get v2() {}, set v2(bar) {}, get i2() {}, set v1(baz) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            errors: [
+                { message: "Getter is not present for setter 'i1'.", type: "Property", column: 24 },
+                { message: "Setter is not present for getter 'i2'.", type: "Property", column: 69 }
+            ]
+        },
+
+        // In the case of duplicates which don't have the other kind, all nodes are reported
+        {
+            code: "var o = { get a() {}, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 11 },
+                { message: "Setter is not present for getter 'a'.", type: "Property", column: 23 }
+            ]
+        },
+        {
+            code: "var o = { set a(foo) {}, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 11 },
+                { message: "Getter is not present for setter 'a'.", type: "Property", column: 26 }
+            ]
+        },
+
+        // Other elements or even value property duplicates in the same literal do not affect this rule
+        {
+            code: "var o = { a, get b() {}, c };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter 'b'.", type: "Property", column: 14 }]
+        },
+        {
+            code: "var o = { a, get b() {}, c, set d(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Setter is not present for getter 'b'.", type: "Property", column: 14 },
+                { message: "Getter is not present for setter 'd'.", type: "Property", column: 29 }
+            ]
+        },
+        {
+            code: "var o = { get a() {}, a:1 };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { a, get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 14 }]
+        },
+        {
+            code: "var o = { set a(foo) {}, a:1 };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { a, set a(foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 14 }]
+        },
+        {
+            code: "var o = { get a() {}, ...b };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { get a() {}, ...a };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "Setter is not present for getter 'a'.", type: "Property", column: 11 }]
+        },
+        {
+            code: "var o = { set a(foo) {}, ...a };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "Getter is not present for setter 'a'.", type: "Property", column: 11 }]
+        },
+
+        // Full location tests
+        {
+            code: "var o = { get a() {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                message: "Setter is not present for getter 'a'.",
+                type: "Property",
+                line: 1,
+                column: 11,
+                endLine: 1,
+                endColumn: 16
+            }]
+        },
+        {
+            code: "var o = {\n  set [\n a](foo) {} };",
+            options: [{ setWithoutGet: true, getWithoutSet: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                message: "Getter is not present for setter.",
+                type: "Property",
+                line: 2,
+                column: 3,
+                endLine: 3,
+                endColumn: 4
+            }]
+        },
+
+        //------------------------------------------------------------------------------
+        // Property descriptors
+        //------------------------------------------------------------------------------
+
         {
             code: "var o = {d: 1};\n Object.defineProperty(o, 'c', \n{set: function(value) {\n val = value; \n} \n});",
-            errors: [getterError]
+            errors: [{ message: "Getter is not present in property descriptor.", type: "ObjectExpression" }]
         },
         {
             code: "Reflect.defineProperty(obj, 'foo', {set: function(value) {}});",
-            errors: [getterError]
+            errors: [{ message: "Getter is not present in property descriptor.", type: "ObjectExpression" }]
         },
         {
             code: "Object.defineProperties(obj, {foo: {set: function(value) {}}});",
-            errors: [getterError]
+            errors: [{ message: "Getter is not present in property descriptor.", type: "ObjectExpression" }]
         },
         {
             code: "Object.create(null, {foo: {set: function(value) {}}});",
-            errors: [getterError]
-        },
-        {
-            code: "var expr = 'foo';  var o = { set [expr](value) { val = value; } };",
-            parserOptions: { ecmaVersion: 6 },
-            errors: [getterError]
+            errors: [{ message: "Getter is not present in property descriptor.", type: "ObjectExpression" }]
         }
     ]
 });
diff --git a/tests/lib/rules/class-methods-use-this.js b/tests/lib/rules/class-methods-use-this.js
index 89af434fd..5238b9d68 100644
--- a/tests/lib/rules/class-methods-use-this.js
+++ b/tests/lib/rules/class-methods-use-this.js
@@ -37,49 +37,49 @@ ruleTester.run("class-methods-use-this", rule, {
             code: "class A { foo() {} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() {/**this**/} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() {var a = function () {this};} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() {var a = function () {var b = function(){this}};} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() {window.this} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() {that.this = 'this';} }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
             code: "class A { foo() { () => undefined; } }",
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
@@ -87,7 +87,7 @@ ruleTester.run("class-methods-use-this", rule, {
             options: [{ exceptMethods: ["bar"] }],
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 14, messageId: "missingThis", data: { name: "method 'foo'" } }
             ]
         },
         {
@@ -95,7 +95,7 @@ ruleTester.run("class-methods-use-this", rule, {
             options: [{ exceptMethods: ["foo"] }],
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 34, messageId: "missingThis", data: { name: "hasOwnProperty" } }
+                { type: "FunctionExpression", line: 1, column: 34, messageId: "missingThis", data: { name: "method 'hasOwnProperty'" } }
             ]
         },
         {
@@ -103,7 +103,22 @@ ruleTester.run("class-methods-use-this", rule, {
             options: [{ exceptMethods: ["foo"] }],
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { type: "FunctionExpression", line: 1, column: 16, messageId: "missingThis", data: { name: "foo" } }
+                { type: "FunctionExpression", line: 1, column: 16, messageId: "missingThis", data: { name: "method" } }
+            ]
+        },
+        {
+            code: "class A { foo(){} 'bar'(){} 123(){} [`baz`](){} [a](){} [f(a)](){} get quux(){} set[a](b){} *quuux(){} }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                { message: "Expected 'this' to be used by class method 'foo'.", type: "FunctionExpression", column: 14 },
+                { message: "Expected 'this' to be used by class method 'bar'.", type: "FunctionExpression", column: 24 },
+                { message: "Expected 'this' to be used by class method '123'.", type: "FunctionExpression", column: 32 },
+                { message: "Expected 'this' to be used by class method 'baz'.", type: "FunctionExpression", column: 44 },
+                { message: "Expected 'this' to be used by class method.", type: "FunctionExpression", column: 52 },
+                { message: "Expected 'this' to be used by class method.", type: "FunctionExpression", column: 63 },
+                { message: "Expected 'this' to be used by class getter 'quux'.", type: "FunctionExpression", column: 76 },
+                { message: "Expected 'this' to be used by class setter.", type: "FunctionExpression", column: 87 },
+                { message: "Expected 'this' to be used by class generator method 'quuux'.", type: "FunctionExpression", column: 99 }
             ]
         }
     ]
diff --git a/tests/lib/rules/dot-notation.js b/tests/lib/rules/dot-notation.js
index 490a0956c..5532ea358 100644
--- a/tests/lib/rules/dot-notation.js
+++ b/tests/lib/rules/dot-notation.js
@@ -57,7 +57,8 @@ ruleTester.run("dot-notation", rule, {
         "a.null;",
         "a[undefined];",
         "a[void 0];",
-        "a[b()];"
+        "a[b()];",
+        { code: "a[/(?<zero>0)/];", parserOptions: { ecmaVersion: 2018 } }
     ],
     invalid: [
         {
@@ -82,6 +83,16 @@ ruleTester.run("dot-notation", rule, {
             output: "a.null;",
             errors: [{ messageId: "useDot", data: { key: "null" } }]
         },
+        {
+            code: "a[true];",
+            output: "a.true;",
+            errors: [{ messageId: "useDot", data: { key: "true" } }]
+        },
+        {
+            code: "a[false];",
+            output: "a.false;",
+            errors: [{ messageId: "useDot", data: { key: "false" } }]
+        },
         {
             code: "a['b'];",
             output: "a.b;",
diff --git a/tests/lib/rules/function-call-argument-newline.js b/tests/lib/rules/function-call-argument-newline.js
new file mode 100644
index 000000000..2871534e7
--- /dev/null
+++ b/tests/lib/rules/function-call-argument-newline.js
@@ -0,0 +1,386 @@
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/function-call-argument-newline"),
+    { RuleTester } = require("../../../lib/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+ruleTester.run("function-call-argument-newline", rule, {
+    valid: [
+
+        /* early return */
+        "fn()",
+        "fn(a)",
+        "new Foo()",
+        "new Foo(b)",
+
+        /* default ("always") */
+        "fn(a,\n\tb)",
+
+        /* "always" */
+        { code: "fn(a,\n\tb)", options: ["always"] },
+        { code: "fn(\n\ta,\n\tb\n)", options: ["always"] },
+        { code: "fn(\n\ta,\n\tb,\n\tc\n)", options: ["always"] },
+        {
+            code: "fn(\n\ta,\n\tb,\n\t[\n\t\t1,\n\t\t2\n\t]\n)",
+            options: ["always"]
+        },
+        {
+            code: "fn(\n\ta,\n\tb,\n\t{\n\t\ta: 1,\n\t\tb: 2\n\t}\n)",
+            options: ["always"]
+        },
+        {
+            code: "fn(\n\ta,\n\tb,\n\tfunction (x) {\n\t\tx()\n\t}\n)",
+            options: ["always"]
+        },
+        {
+            code: "fn(\n\ta,\n\tb,\n\tx => {\n\t\tx()\n\t}\n)",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        /* "never" */
+        { code: "fn(a, b)", options: ["never"] },
+        { code: "fn(\n\ta, b\n)", options: ["never"] },
+        { code: "fn(a, b, c)", options: ["never"] },
+        { code: "fn(a, b, [\n\t1,\n\t2\n])", options: ["never"] },
+        { code: "fn(a, b, {\n\ta: 1,\n\tb: 2\n})", options: ["never"] },
+        { code: "fn(a, b, function (x) {\n\tx()\n})", options: ["never"] },
+        {
+            code: "fn(a, b, x => {\n\tx()\n})",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 6 }
+        },
+
+        /* "consistent" */
+        { code: "fn(a, b, c)", options: ["consistent"] },
+        { code: "fn(a,\n\tb,\n\tc)", options: ["consistent"] }
+    ],
+    invalid: [
+
+        /* default ("always") */
+        {
+            code: "fn(a, b)",
+            output: "fn(a,\nb)",
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                }
+            ]
+        },
+
+        /* "always" */
+        {
+            code: "fn(a, b)",
+            output: "fn(a,\nb)",
+            options: ["always"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                }
+            ]
+        },
+        {
+            code: "fn(a, b, c)",
+            output: "fn(a,\nb,\nc)",
+            options: ["always"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                },
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 1,
+                    endColumn: 10
+                }
+            ]
+        },
+        {
+            code: "fn(a, b, [\n\t1,\n\t2\n])",
+            output: "fn(a,\nb,\n[\n\t1,\n\t2\n])",
+            options: ["always"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                },
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 1,
+                    endColumn: 10
+                }
+            ]
+        },
+        {
+            code: "fn(a, b, {\n\ta: 1,\n\tb: 2\n})",
+            output: "fn(a,\nb,\n{\n\ta: 1,\n\tb: 2\n})",
+            options: ["always"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                },
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 1,
+                    endColumn: 10
+                }
+            ]
+        },
+        {
+            code: "fn(a, b, function (x) {\n\tx()\n})",
+            output: "fn(a,\nb,\nfunction (x) {\n\tx()\n})",
+            options: ["always"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                },
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 1,
+                    endColumn: 10
+                }
+            ]
+        },
+        {
+            code: "fn(a, b, x => {\n\tx()\n})",
+            output: "fn(a,\nb,\nx => {\n\tx()\n})",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 7
+                },
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 1,
+                    endColumn: 10
+                }
+            ]
+        },
+
+        /* "never" */
+        {
+            code: "fn(a,\n\tb)",
+            output: "fn(a, b)",
+            options: ["never"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb,\n\tc)",
+            output: "fn(a, b, c)",
+            options: ["never"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                },
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb,\n\t[\n\t\t1,\n\t\t2\n])",
+            output: "fn(a, b, [\n\t\t1,\n\t\t2\n])",
+            options: ["never"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                },
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb,\n\t{\n\t\ta: 1,\n\t\tb: 2\n})",
+            output: "fn(a, b, {\n\t\ta: 1,\n\t\tb: 2\n})",
+            options: ["never"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                },
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb,\n\tfunction (x) {\n\t\tx()\n})",
+            output: "fn(a, b, function (x) {\n\t\tx()\n})",
+            options: ["never"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                },
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb,\n\tx => {\n\t\tx()\n})",
+            output: "fn(a, b, x => {\n\t\tx()\n})",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 6,
+                    endLine: 2,
+                    endColumn: 2
+                },
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 2
+                }
+            ]
+        },
+
+        /* "consistent" */
+        {
+            code: "fn(a, b,\n\tc)",
+            output: "fn(a, b, c)",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "unexpectedLineBreak",
+                    line: 1,
+                    column: 9,
+                    endLine: 2,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb, c)",
+            output: "fn(a,\n\tb,\nc)",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 2,
+                    column: 4,
+                    endLine: 2,
+                    endColumn: 5
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb /* comment */, c)",
+            output: "fn(a,\n\tb /* comment */,\nc)",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 2,
+                    column: 18,
+                    endLine: 2,
+                    endColumn: 19
+                }
+            ]
+        },
+        {
+            code: "fn(a,\n\tb, /* comment */ c)",
+            output: "fn(a,\n\tb, /* comment */\nc)",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 2,
+                    column: 18,
+                    endLine: 2,
+                    endColumn: 19
+                }
+            ]
+        }
+    ]
+});
diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js
index 518f6c36c..a0a1e7a8c 100644
--- a/tests/lib/rules/no-dupe-keys.js
+++ b/tests/lib/rules/no-dupe-keys.js
@@ -22,6 +22,11 @@ ruleTester.run("no-dupe-keys", rule, {
     valid: [
         "var foo = { __proto__: 1, two: 2};",
         "var x = { foo: 1, bar: 2 };",
+        "var x = { '': 1, bar: 2 };",
+        "var x = { '': 1, ' ': 2 };",
+        { code: "var x = { '': 1, [null]: 2 };", parserOptions: { ecmaVersion: 6 } },
+        { code: "var x = { '': 1, [a]: 2 };", parserOptions: { ecmaVersion: 6 } },
+        { code: "var x = { [a]: 1, [a]: 2 };", parserOptions: { ecmaVersion: 6 } },
         "+{ get a() { }, set a(b) { } };",
         { code: "var x = { a: b, [a]: b };", parserOptions: { ecmaVersion: 6 } },
         { code: "var x = { a: b, ...c }", parserOptions: { ecmaVersion: 2018 } },
@@ -32,6 +37,8 @@ ruleTester.run("no-dupe-keys", rule, {
     invalid: [
         { code: "var x = { a: b, ['a']: b };", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", data: { name: "a" }, type: "ObjectExpression" }] },
         { code: "var x = { y: 1, y: 2 };", errors: [{ messageId: "unexpected", data: { name: "y" }, type: "ObjectExpression" }] },
+        { code: "var x = { '': 1, '': 2 };", errors: [{ messageId: "unexpected", data: { name: "" }, type: "ObjectExpression" }] },
+        { code: "var x = { '': 1, [``]: 2 };", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", data: { name: "" }, type: "ObjectExpression" }] },
         { code: "var foo = { 0x1: 1, 1: 2};", errors: [{ messageId: "unexpected", data: { name: "1" }, type: "ObjectExpression" }] },
         { code: "var x = { \"z\": 1, z: 2 };", errors: [{ messageId: "unexpected", data: { name: "z" }, type: "ObjectExpression" }] },
         { code: "var foo = {\n  bar: 1,\n  bar: 1,\n}", errors: [{ messageId: "unexpected", data: { name: "bar" }, line: 3, column: 3 }] },
diff --git a/tests/lib/rules/no-duplicate-case.js b/tests/lib/rules/no-duplicate-case.js
index 21f6267a0..a6e8e0ff3 100644
--- a/tests/lib/rules/no-duplicate-case.js
+++ b/tests/lib/rules/no-duplicate-case.js
@@ -29,71 +29,105 @@ ruleTester.run("no-duplicate-case", rule, {
         "var a = 1, f = function(s) { return { p1: s } }; switch (a) {case f(a + 1).p1: break; case f(a + 2).p1: break; default: break;}",
         "var a = 1, f = function(s) { return { p1: s } }; switch (a) {case f(a == 1 ? 2 : 3).p1: break; case f(a === 1 ? 2 : 3).p1: break; default: break;}",
         "var a = 1, f1 = function() { return { p1: 1 } }, f2 = function() { return { p1: 2 } }; switch (a) {case f1().p1: break; case f2().p1: break; default: break;}",
-        "var a = [1,2]; switch(a.toString()){case ([1,2]).toString():break; case ([1]).toString():break; default:break;}"
+        "var a = [1,2]; switch(a.toString()){case ([1,2]).toString():break; case ([1]).toString():break; default:break;}",
+        "switch(a) { case a: break; } switch(a) { case a: break; }",
+        "switch(a) { case toString: break; }"
     ],
     invalid: [
         {
             code: "var a = 1; switch (a) {case 1: break; case 1: break; case 2: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 39
             }]
         },
         {
             code: "var a = '1'; switch (a) {case '1': break; case '1': break; case '2': break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 43
             }]
         },
         {
             code: "var a = 1, one = 1; switch (a) {case one: break; case one: break; case 2: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 50
             }]
         },
         {
             code: "var a = 1, p = {p: {p1: 1, p2: 1}}; switch (a) {case p.p.p1: break; case p.p.p1: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 69
             }]
         },
         {
             code: "var a = 1, f = function(b) { return b ? { p1: 1 } : { p1: 2 }; }; switch (a) {case f(true).p1: break; case f(true).p1: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 103
             }]
         },
         {
             code: "var a = 1, f = function(s) { return { p1: s } }; switch (a) {case f(a + 1).p1: break; case f(a + 1).p1: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 87
             }]
         },
         {
             code: "var a = 1, f = function(s) { return { p1: s } }; switch (a) {case f(a === 1 ? 2 : 3).p1: break; case f(a === 1 ? 2 : 3).p1: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 97
             }]
         },
         {
             code: "var a = 1, f1 = function() { return { p1: 1 } }; switch (a) {case f1().p1: break; case f1().p1: break; default: break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 83
             }]
         },
         {
             code: "var a = [1, 2]; switch(a.toString()){case ([1, 2]).toString():break; case ([1, 2]).toString():break; default:break;}",
             errors: [{
                 messageId: "unexpected",
-                type: "SwitchCase"
+                type: "SwitchCase",
+                column: 70
             }]
+        },
+        {
+            code: "switch (a) { case a: case a: }",
+            errors: [{
+                messageId: "unexpected",
+                type: "SwitchCase",
+                column: 22
+            }]
+        },
+        {
+            code: "switch (a) { case a: break; case b: break; case a: break; case c: break; case a: break; }",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "SwitchCase",
+                    column: 44
+                },
+                {
+                    messageId: "unexpected",
+                    type: "SwitchCase",
+                    column: 74
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/no-extra-bind.js b/tests/lib/rules/no-extra-bind.js
index e9c72bca6..cc2b164e8 100644
--- a/tests/lib/rules/no-extra-bind.js
+++ b/tests/lib/rules/no-extra-bind.js
@@ -21,6 +21,7 @@ const errors = [{ messageId: "unexpected", type: "CallExpression" }];
 ruleTester.run("no-extra-bind", rule, {
     valid: [
         "var a = function(b) { return b }.bind(c, d)",
+        { code: "var a = function(b) { return b }.bind(...c)", parserOptions: { ecmaVersion: 6 } },
         "var a = function() { this.b }()",
         "var a = function() { this.b }.foo()",
         "var a = f.bind(a)",
diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js
index 4d2890e84..129329ff0 100644
--- a/tests/lib/rules/no-extra-boolean-cast.js
+++ b/tests/lib/rules/no-extra-boolean-cast.js
@@ -227,6 +227,314 @@ ruleTester.run("no-extra-boolean-cast", rule, {
                 messageId: "unexpectedCall",
                 type: "CallExpression"
             }]
+        },
+        {
+            code: "if (!Boolean()) { foo() }",
+            output: "if (true) { foo() }",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "while (!Boolean()) { foo() }",
+            output: "while (true) { foo() }",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "var foo = Boolean() ? bar() : baz()",
+            output: "var foo = false ? bar() : baz()",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if (Boolean()) { foo() }",
+            output: "if (false) { foo() }",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "while (Boolean()) { foo() }",
+            output: "while (false) { foo() }",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+
+        // Adjacent tokens tests
+        {
+            code: "void!Boolean()",
+            output: "void true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "void! Boolean()",
+            output: "void true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "typeof!Boolean()",
+            output: "typeof true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "(!Boolean())",
+            output: "(true)",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "+!Boolean()",
+            output: "+true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "void !Boolean()",
+            output: "void true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "void(!Boolean())",
+            output: "void(true)",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "void/**/!Boolean()",
+            output: "void/**/true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+
+        // Comments tests
+        {
+            code: "!/**/!!foo",
+            output: "!/**/foo",
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "!!/**/!foo",
+            output: null,
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "!!!/**/foo",
+            output: null,
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "!!!foo/**/",
+            output: "!foo/**/",
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "if(!/**/!foo);",
+            output: null,
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "(!!/**/foo ? 1 : 2)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedNegation",
+                type: "UnaryExpression"
+            }]
+        },
+        {
+            code: "!/**/Boolean(foo)",
+            output: "!/**/foo",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean/**/(foo)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean(/**/foo)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean(foo/**/)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean(foo)/**/",
+            output: "!foo/**/",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(Boolean/**/(foo));",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "(Boolean(foo/**/) ? 1 : 2)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "/**/!Boolean()",
+            output: "/**/true",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!/**/Boolean()",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean/**/()",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean(/**/)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "!Boolean()/**/",
+            output: "true/**/",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(!/**/Boolean());",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "(!Boolean(/**/) ? 1 : 2)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(/**/Boolean());",
+            output: "if(/**/false);",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(Boolean/**/());",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(Boolean(/**/));",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "if(Boolean()/**/);",
+            output: "if(false/**/);",
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
+        },
+        {
+            code: "(Boolean/**/() ? 1 : 2)",
+            output: null,
+            errors: [{
+                messageId: "unexpectedCall",
+                type: "CallExpression"
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 6c6eeb2a1..86b5ae4d6 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -1197,6 +1197,12 @@ ruleTester.run("no-extra-parens", rule, {
             "Identifier",
             1
         ),
+        invalid("let s = `${(v)}`", "let s = `${v}`", "Identifier"),
+        invalid("let s = `${(a, b)}`", "let s = `${a, b}`", "SequenceExpression"),
+        invalid("function foo(a = (b)) {}", "function foo(a = b) {}", "Identifier"),
+        invalid("const bar = (a = (b)) => a", "const bar = (a = b) => a", "Identifier"),
+        invalid("const [a = (b)] = []", "const [a = b] = []", "Identifier"),
+        invalid("const {a = (b)} = {}", "const {a = b} = {}", "Identifier"),
 
         // https://github.com/eslint/eslint/issues/11706 (also in valid[])
         {
diff --git a/tests/lib/rules/no-mixed-operators.js b/tests/lib/rules/no-mixed-operators.js
index d740b8562..4e822181f 100644
--- a/tests/lib/rules/no-mixed-operators.js
+++ b/tests/lib/rules/no-mixed-operators.js
@@ -47,7 +47,18 @@ ruleTester.run("no-mixed-operators", rule, {
         {
             code: "a * b / c",
             options: [{ allowSamePrecedence: true }]
-        }
+        },
+        {
+            code: "(a || b) ? c : d",
+            options: [{ groups: [["&&", "||", "?:"]] }]
+        },
+        {
+            code: "a || (b ? c : d)",
+            options: [{ groups: [["&&", "||", "?:"]] }]
+        },
+        "a || (b ? c : d)",
+        "(a || b) ? c : d",
+        "a || b ? c : d"
     ],
     invalid: [
         {
@@ -110,6 +121,38 @@ ruleTester.run("no-mixed-operators", rule, {
                 { column: 3, message: "Unexpected mix of '*' and '/'." },
                 { column: 7, message: "Unexpected mix of '*' and '/'." }
             ]
+        },
+        {
+            code: "a || b ? c : d",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '||' and '?:'." },
+                { column: 8, message: "Unexpected mix of '||' and '?:'." }
+            ]
+        },
+        {
+            code: "a && b ? 1 : 2",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '&&' and '?:'." },
+                { column: 8, message: "Unexpected mix of '&&' and '?:'." }
+            ]
+        },
+        {
+            code: "x ? a && b : 0",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 7, message: "Unexpected mix of '?:' and '&&'." }
+            ]
+        },
+        {
+            code: "x ? 0 : a && b",
+            options: [{ groups: [["&&", "||", "?:"]] }],
+            errors: [
+                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 11, message: "Unexpected mix of '?:' and '&&'." }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/prefer-template.js b/tests/lib/rules/prefer-template.js
index 9e987a813..439b261cc 100644
--- a/tests/lib/rules/prefer-template.js
+++ b/tests/lib/rules/prefer-template.js
@@ -199,6 +199,16 @@ ruleTester.run("prefer-template", rule, {
             output: null,
             errors
         },
+        {
+            code: "foo + '\\0\\1'",
+            output: null,
+            errors
+        },
+        {
+            code: "foo + '\\08'",
+            output: null,
+            errors
+        },
         {
             code: "foo + '\\\\033'",
             output: "`${foo  }\\\\033`",
diff --git a/tests/lib/rules/require-await.js b/tests/lib/rules/require-await.js
index c63a1ef5e..7b43f3266 100644
--- a/tests/lib/rules/require-await.js
+++ b/tests/lib/rules/require-await.js
@@ -72,6 +72,10 @@ ruleTester.run("require-await", rule, {
             code: "(class { async foo() { doSomething() } })",
             errors: ["Async method 'foo' has no 'await' expression."]
         },
+        {
+            code: "(class { async ''() { doSomething() } })",
+            errors: ["Async method '' has no 'await' expression."]
+        },
         {
             code: "async function foo() { async () => { await doSomething() } }",
             errors: ["Async function 'foo' has no 'await' expression."]
diff --git a/tests/lib/rules/sort-keys.js b/tests/lib/rules/sort-keys.js
index de2eeef1e..eb26c5250 100644
--- a/tests/lib/rules/sort-keys.js
+++ b/tests/lib/rules/sort-keys.js
@@ -22,6 +22,10 @@ ruleTester.run("sort-keys", rule, {
     valid: [
 
         // default (asc)
+        { code: "var obj = {'':1, [``]:2}", options: [], parserOptions: { ecmaVersion: 6 } },
+        { code: "var obj = {[``]:1, '':2}", options: [], parserOptions: { ecmaVersion: 6 } },
+        { code: "var obj = {'':1, a:2}", options: [] },
+        { code: "var obj = {[``]:1, a:2}", options: [], parserOptions: { ecmaVersion: 6 } },
         { code: "var obj = {_:2, a:1, b:3} // default", options: [] },
         { code: "var obj = {a:1, b:3, c:2}", options: [] },
         { code: "var obj = {a:2, b:3, b_:1}", options: [] },
@@ -32,6 +36,8 @@ ruleTester.run("sort-keys", rule, {
 
         // ignore non-simple computed properties.
         { code: "var obj = {a:1, b:3, [a + b]: -1, c:2}", options: [], parserOptions: { ecmaVersion: 6 } },
+        { code: "var obj = {'':1, [f()]:2, a:3}", options: [], parserOptions: { ecmaVersion: 6 } },
+        { code: "var obj = {a:1, [b++]:2, '':3}", options: ["desc"], parserOptions: { ecmaVersion: 6 } },
 
         // ignore properties separated by spread properties
         { code: "var obj = {a:1, ...z, b:1}", options: [], parserOptions: { ecmaVersion: 2018 } },
@@ -39,6 +45,8 @@ ruleTester.run("sort-keys", rule, {
         { code: "var obj = {...a, b:1, ...c, d:1}", options: [], parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = {...a, b:1, ...d, ...c, e:2, z:5}", options: [], parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = {b:1, ...c, ...d, e:2}", options: [], parserOptions: { ecmaVersion: 2018 } },
+        { code: "var obj = {a:1, ...z, '':2}", options: [], parserOptions: { ecmaVersion: 2018 } },
+        { code: "var obj = {'':1, ...z, 'a':2}", options: ["desc"], parserOptions: { ecmaVersion: 2018 } },
 
         // not ignore properties not separated by spread properties
         { code: "var obj = {...z, a:1, b:1}", options: [], parserOptions: { ecmaVersion: 2018 } },
@@ -159,6 +167,15 @@ ruleTester.run("sort-keys", rule, {
     invalid: [
 
         // default (asc)
+        {
+            code: "var obj = {a:1, '':2} // default",
+            errors: ["Expected object keys to be in ascending order. '' should be before 'a'."]
+        },
+        {
+            code: "var obj = {a:1, [``]:2} // default",
+            parserOptions: { ecmaVersion: 6 },
+            errors: ["Expected object keys to be in ascending order. '' should be before 'a'."]
+        },
         {
             code: "var obj = {a:1, _:2, b:3} // default",
             errors: ["Expected object keys to be in ascending order. '_' should be before 'a'."]
@@ -234,6 +251,31 @@ ruleTester.run("sort-keys", rule, {
             parserOptions: { ecmaVersion: 2018 },
             errors: ["Expected object keys to be in descending order. 'b' should be before 'a'."]
         },
+        {
+            code: "var obj = {...z, '':1, a:2}",
+            options: ["desc"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: ["Expected object keys to be in descending order. 'a' should be before ''."]
+        },
+
+        // ignore non-simple computed properties, but their position shouldn't affect other comparisons.
+        {
+            code: "var obj = {a:1, [b+c]:2, '':3}",
+            parserOptions: { ecmaVersion: 6 },
+            errors: ["Expected object keys to be in ascending order. '' should be before 'a'."]
+        },
+        {
+            code: "var obj = {'':1, [b+c]:2, a:3}",
+            options: ["desc"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: ["Expected object keys to be in descending order. 'a' should be before ''."]
+        },
+        {
+            code: "var obj = {b:1, [f()]:2, '':3, a:4}",
+            options: ["desc"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: ["Expected object keys to be in descending order. 'a' should be before ''."]
+        },
 
         // not ignore simple computed properties.
         {
@@ -478,6 +520,21 @@ ruleTester.run("sort-keys", rule, {
         },
 
         // desc
+        {
+            code: "var obj = {'':1, a:'2'} // desc",
+            options: ["desc"],
+            errors: [
+                "Expected object keys to be in descending order. 'a' should be before ''."
+            ]
+        },
+        {
+            code: "var obj = {[``]:1, a:'2'} // desc",
+            options: ["desc"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                "Expected object keys to be in descending order. 'a' should be before ''."
+            ]
+        },
         {
             code: "var obj = {a:1, _:2, b:3} // desc",
             options: ["desc"],
diff --git a/tests/lib/rules/utils/ast-utils.js b/tests/lib/rules/utils/ast-utils.js
index 678b7f274..314deeadf 100644
--- a/tests/lib/rules/utils/ast-utils.js
+++ b/tests/lib/rules/utils/ast-utils.js
@@ -671,7 +671,9 @@ describe("ast-utils", () => {
             "async () => {}": "async arrow function",
             "({ foo: function foo() {} })": "method 'foo'",
             "({ foo: function() {} })": "method 'foo'",
+            "({ '': function() {} })": "method ''",
             "({ ['foo']: function() {} })": "method 'foo'",
+            "({ ['']: function() {} })": "method ''",
             "({ [foo]: function() {} })": "method",
             "({ foo() {} })": "method 'foo'",
             "({ foo: function* foo() {} })": "generator method 'foo'",
@@ -1248,4 +1250,82 @@ describe("ast-utils", () => {
             assert.strictEqual(astUtils.equalTokens(ast.body[0], ast.body[1], sourceCode), false);
         });
     });
+
+    describe("hasOctalEscapeSequence", () => {
+
+        /* eslint-disable quote-props */
+        const expectedResults = {
+            "\\1": true,
+            "\\2": true,
+            "\\7": true,
+            "\\00": true,
+            "\\01": true,
+            "\\02": true,
+            "\\07": true,
+            "\\08": true,
+            "\\09": true,
+            "\\10": true,
+            "\\12": true,
+            " \\1": true,
+            "\\1 ": true,
+            "a\\1": true,
+            "\\1a": true,
+            "a\\1a": true,
+            " \\01": true,
+            "\\01 ": true,
+            "a\\01": true,
+            "\\01a": true,
+            "a\\01a": true,
+            "a\\08a": true,
+            "\\0\\1": true,
+            "\\0\\01": true,
+            "\\0\\08": true,
+            "\\n\\1": true,
+            "\\n\\01": true,
+            "\\n\\08": true,
+            "\\\\\\1": true,
+            "\\\\\\01": true,
+            "\\\\\\08": true,
+
+            "\\0": false,
+            "\\8": false,
+            "\\9": false,
+            " \\0": false,
+            "\\0 ": false,
+            "a\\0": false,
+            "\\0a": false,
+            "a\\8a": false,
+            "\\0\\8": false,
+            "\\8\\0": false,
+            "\\80": false,
+            "\\81": false,
+            "\\\\": false,
+            "\\\\0": false,
+            "\\\\01": false,
+            "\\\\08": false,
+            "\\\\1": false,
+            "\\\\12": false,
+            "\\\\\\0": false,
+            "\\\\\\8": false,
+            "\\0\\\\": false,
+            "0": false,
+            "1": false,
+            "8": false,
+            "01": false,
+            "08": false,
+            "80": false,
+            "12": false,
+            "\\a": false,
+            "\\n": false
+        };
+        /* eslint-enable quote-props */
+
+        Object.keys(expectedResults).forEach(key => {
+            it(`should return ${expectedResults[key]} for ${key}`, () => {
+                const ast = espree.parse(`"${key}"`);
+
+                assert.strictEqual(astUtils.hasOctalEscapeSequence(ast.body[0].expression.raw), expectedResults[key]);
+            });
+        });
+    });
 });
diff --git a/tests/lib/rules/yoda.js b/tests/lib/rules/yoda.js
index 89979ff58..d2c183477 100644
--- a/tests/lib/rules/yoda.js
+++ b/tests/lib/rules/yoda.js
@@ -50,6 +50,14 @@ ruleTester.run("yoda", rule, {
         }, {
             code: "if ('blue' < x.y && x.y < 'green') {}",
             options: ["never", { exceptRange: true }]
+        }, {
+            code: "if (0 < x[``] && x[``] < 100) {}",
+            options: ["never", { exceptRange: true }],
+            parserOptions: { ecmaVersion: 2015 }
+        }, {
+            code: "if (0 < x[''] && x[``] < 100) {}",
+            options: ["never", { exceptRange: true }],
+            parserOptions: { ecmaVersion: 2015 }
         }, {
             code: "if (0 <= x['y'] && x['y'] <= 100) {}",
             options: ["never", { exceptRange: true }]
@@ -332,6 +340,66 @@ ruleTester.run("yoda", rule, {
                 }
             ]
         },
+        {
+            code: "if (0 <= a[''] && a.b < 1) {}",
+            output: "if (a[''] >= 0 && a.b < 1) {}",
+            options: ["never", { exceptRange: true }],
+            errors: [
+                {
+                    messageId: "expected",
+                    data: { expectedSide: "right", operator: "<=" },
+                    type: "BinaryExpression"
+                }
+            ]
+        },
+        {
+            code: "if (0 <= a[''] && a[' '] < 1) {}",
+            output: "if (a[''] >= 0 && a[' '] < 1) {}",
+            options: ["never", { exceptRange: true }],
+            errors: [
+                {
+                    messageId: "expected",
+                    data: { expectedSide: "right", operator: "<=" },
+                    type: "BinaryExpression"
+                }
+            ]
+        },
+        {
+            code: "if (0 <= a[''] && a[null] < 1) {}",
+            output: "if (a[''] >= 0 && a[null] < 1) {}",
+            options: ["never", { exceptRange: true }],
+            errors: [
+                {
+                    messageId: "expected",
+                    data: { expectedSide: "right", operator: "<=" },
+                    type: "BinaryExpression"
+                }
+            ]
+        },
+        {
+            code: "if (0 <= a[''] && a[b] < 1) {}",
+            output: "if (a[''] >= 0 && a[b] < 1) {}",
+            options: ["never", { exceptRange: true }],
+            errors: [
+                {
+                    messageId: "expected",
+                    data: { expectedSide: "right", operator: "<=" },
+                    type: "BinaryExpression"
+                }
+            ]
+        },
+        {
+            code: "if (0 <= a[''] && a[b()] < 1) {}",
+            output: "if (a[''] >= 0 && a[b()] < 1) {}",
+            options: ["never", { exceptRange: true }],
+            errors: [
+                {
+                    messageId: "expected",
+                    data: { expectedSide: "right", operator: "<=" },
+                    type: "BinaryExpression"
+                }
+            ]
+        },
         {
             code: "if (0 <= a[b()] && a[b()] < 1) {}",
             output: "if (a[b()] >= 0 && a[b()] < 1) {}",