diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -319,6 +319,8 @@ 'ArcanistTestXHPASTLintSwitchHook' => 'lint/linter/__tests__/ArcanistTestXHPASTLintSwitchHook.php', 'ArcanistTextLinter' => 'lint/linter/ArcanistTextLinter.php', 'ArcanistTextLinterTestCase' => 'lint/linter/__tests__/ArcanistTextLinterTestCase.php', + 'ArcanistThisReassignmentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php', + 'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php', 'ArcanistTimeWorkflow' => 'workflow/ArcanistTimeWorkflow.php', 'ArcanistToStringExceptionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php', 'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistToStringExceptionXHPASTLinterRuleTestCase.php', @@ -695,6 +697,8 @@ 'ArcanistTestXHPASTLintSwitchHook' => 'ArcanistXHPASTLintSwitchHook', 'ArcanistTextLinter' => 'ArcanistLinter', 'ArcanistTextLinterTestCase' => 'ArcanistLinterTestCase', + 'ArcanistThisReassignmentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistTimeWorkflow' => 'ArcanistPhrequentWorkflow', 'ArcanistToStringExceptionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', diff --git a/src/lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php @@ -0,0 +1,39 @@ +selectDescendantsOfType('n_BINARY_EXPRESSION'); + + foreach ($binary_expressions as $binary_expression) { + $operator = $binary_expression->getChildOfType(1, 'n_OPERATOR'); + + if ($operator->getConcreteString() != '=') { + continue; + } + + $variable = $binary_expression->getChildByIndex(0); + + if ($variable->getTypeName() != 'n_VARIABLE') { + continue; + } + + if ($variable->getConcreteString() == '$this') { + $this->raiseLintAtNode( + $binary_expression, + pht( + '`%s` cannot be re-assigned. '. + 'This construct will cause a PHP fatal error.', + '$this')); + } + } + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php b/src/lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php @@ -0,0 +1,10 @@ +executeTestsInDirectory(dirname(__FILE__).'/this-reassignment/'); + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/this-reassignment/class.lint-test b/src/lint/linter/xhpast/rules/__tests__/this-reassignment/class.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/this-reassignment/class.lint-test @@ -0,0 +1,8 @@ +