diff --git a/src/lint/linter/apachelicense/__init__.php b/src/lint/linter/apachelicense/__init__.php index f16cf6da..08dd7e0e 100644 --- a/src/lint/linter/apachelicense/__init__.php +++ b/src/lint/linter/apachelicense/__init__.php @@ -6,7 +6,6 @@ -phutil_require_module('arcanist', 'exception/usage'); phutil_require_module('arcanist', 'lint/linter/base'); diff --git a/src/lint/linter/xhpast/ArcanistXHPASTLinter.php b/src/lint/linter/xhpast/ArcanistXHPASTLinter.php index e1c292d0..e9351731 100644 --- a/src/lint/linter/xhpast/ArcanistXHPASTLinter.php +++ b/src/lint/linter/xhpast/ArcanistXHPASTLinter.php @@ -39,6 +39,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter { const LINT_EXIT_EXPRESSION = 17; const LINT_COMMENT_STYLE = 18; const LINT_CLASS_FILENAME_MISMATCH = 19; + const LINT_TAUTOLOGICAL_EXPRESSION = 20; public function getLintNameMap() { @@ -62,6 +63,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter { self::LINT_EXIT_EXPRESSION => 'Exit Used as Expression', self::LINT_COMMENT_STYLE => 'Comment Style', self::LINT_CLASS_FILENAME_MISMATCH => 'Class-Filename Mismatch', + self::LINT_TAUTOLOGICAL_EXPRESSION => 'Tautological Expression', ); } @@ -108,7 +110,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter { } } } - + public function getXHPASTTreeForPath($path) { return idx($this->trees, $path); } @@ -136,6 +138,42 @@ class ArcanistXHPASTLinter extends ArcanistLinter { $this->lintArrayIndexWhitespace($root); $this->lintHashComments($root); $this->lintPrimaryDeclarationFilenameMatch($root); + $this->lintTautologicalExpressions($root); + } + + private function lintTautologicalExpressions($root) { + $expressions = $root->selectDescendantsOfType('n_BINARY_EXPRESSION'); + + static $operators = array( + '-' => true, + '/' => true, + '-=' => true, + '/=' => true, + '<=' => true, + '<' => true, + '==' => true, + '===' => true, + '>=' => true, + '>' => true, + ); + + foreach ($expressions as $expr) { + $operator = $expr->getChildByIndex(1)->getConcreteString(); + if (empty($operators[$operator])) { + continue; + } + + $left = $expr->getChildByIndex(0)->getSemanticString(); + $right = $expr->getChildByIndex(2)->getSemanticString(); + + if ($left == $right) { + $this->raiseLintAtNode( + $expr, + self::LINT_TAUTOLOGICAL_EXPRESSION, + 'Both sides of this expression are identical, so it always '. + 'evaluates to a constant.'); + } + } } protected function lintHashComments($root) { diff --git a/src/lint/linter/xhpast/__tests__/data/tautological-expressions.lint-test b/src/lint/linter/xhpast/__tests__/data/tautological-expressions.lint-test new file mode 100644 index 00000000..74ea7bcd --- /dev/null +++ b/src/lint/linter/xhpast/__tests__/data/tautological-expressions.lint-test @@ -0,0 +1,18 @@ +m(3) < $x->m(3)) { +} + +if ($y[2] - $y[2]) { +} + +if ($x == $y) { +} + +~~~~~~~~~~ +error:3:5 +error:6:5 +error:9:5 diff --git a/src/workflow/export/ArcanistExportWorkflow.php b/src/workflow/export/ArcanistExportWorkflow.php index 5db19e93..b409a860 100644 --- a/src/workflow/export/ArcanistExportWorkflow.php +++ b/src/workflow/export/ArcanistExportWorkflow.php @@ -166,7 +166,7 @@ EOTEXT case self::SOURCE_LOCAL: $repository_api = $this->getRepositoryAPI(); $parser = new ArcanistDiffParser(); - + if ($repository_api instanceof ArcanistGitAPI) { $this->parseGitRelativeCommit( $repository_api,