Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Added no-tautology-expression rule #4470

Merged
merged 11 commits into from Mar 11, 2019
1 change: 1 addition & 0 deletions src/configs/all.ts
Expand Up @@ -129,6 +129,7 @@ export const rules = {
"no-string-throw": true,
"no-sparse-arrays": true,
"no-submodule-imports": true,
"no-tautology-expression": true,
"no-unbound-method": true,
"no-unnecessary-class": [true, "allow-empty-class"],
"no-unsafe-any": true,
Expand Down
58 changes: 58 additions & 0 deletions src/rules/noTautologyExpressionRule.ts
@@ -0,0 +1,58 @@
/**
* @license
* Copyright 2013 Palantir Technologies, Inc.
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as tsutils from "tsutils";
import * as ts from "typescript";

import * as Lint from "../index";

const TAUTOLOGY_DISCOVERED_ERROR_STRING = "Expression is a tautology. Comparison is redundant.";
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
description: "Enforces that two equal variables or literals are not compared.",
optionExamples: [true],
options: null,
optionsDescription: "Not configurable.",
rationale: `Clean redundant code and unnecessary comparison of objects and literals.`,
ruleName: "no-tautology-expression",
type: "functionality",
typescriptOnly: false,
};

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}

function walk(context: Lint.WalkContext<void>) {
const cb = (node: ts.Node): void => {
if (tsutils.isBinaryExpression(node)) {
if (isLiteral(node.left) && isLiteral(node.right)) {
// Simple textual comparison of both sides
if (node.left.getText() === node.right.getText()) {
JoshuaKGoldberg marked this conversation as resolved.
Show resolved Hide resolved
context.addFailureAtNode(node, TAUTOLOGY_DISCOVERED_ERROR_STRING);
}
}
}
return ts.forEachChild(node, cb);
};
return ts.forEachChild(context.sourceFile, cb);
}

function isLiteral(node: ts.Node): boolean {
return tsutils.isStringLiteral(node) || tsutils.isNumericLiteral(node);
}
30 changes: 30 additions & 0 deletions test/rules/no-tautology-expression/test.ts.lint
@@ -0,0 +1,30 @@
const expr = "someStr" === "someStr";
~~~~~~~~~~~~~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]
const expr = 123 === 123;
~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]
const someVar = 100;
const expr = someVar === someVar;
~~~~~~~~~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]

const someFunc = () => {
if ("SomeStr" === "SomeStr") {
~~~~~~~~~~~~~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]
return true;
}
}

const someFunc = () => {
if (100 === 100) {
~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]
return true;
}
}

const someFunc = () => {
let someVar = 100;
if (someVar === someVar) {
~~~~~~~~~~~~~~~~~~~ [Expression is a tautology. Comparison is redundant.]
return true;
}
}

5 changes: 5 additions & 0 deletions test/rules/no-tautology-expression/tslint.json
@@ -0,0 +1,5 @@
{
"rules": {
"no-tautology-expression": true
}
}