Differential D21539 Diff 51271 src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php
Changeset View
Changeset View
Standalone View
Standalone View
src/lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php
| Show All 16 Lines | public function process(XHPASTNode $root) { | ||||
| foreach ($methods as $method) { | foreach ($methods as $method) { | ||||
| $modifiers = $method->getChildren(); | $modifiers = $method->getChildren(); | ||||
| $is_abstract = false; | $is_abstract = false; | ||||
| $is_final = false; | $is_final = false; | ||||
| $is_static = false; | $is_static = false; | ||||
| $visibility = null; | $visibility = null; | ||||
| $is_property = ($method->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST'); | |||||
| $is_method = !$is_property; | |||||
| $final_modifier = null; | |||||
| $visibility_modifier = null; | |||||
| $abstract_modifier = null; | |||||
| foreach ($modifiers as $modifier) { | foreach ($modifiers as $modifier) { | ||||
| switch ($modifier->getConcreteString()) { | switch ($modifier->getConcreteString()) { | ||||
| case 'abstract': | case 'abstract': | ||||
| if ($method->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST') { | if ($is_property) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht( | pht( | ||||
| 'Properties cannot be declared `%s`.', | 'Properties cannot be declared "abstract".')); | ||||
| 'abstract')); | |||||
| } | } | ||||
| if ($is_abstract) { | if ($is_abstract) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht( | pht( | ||||
| 'Multiple `%s` modifiers are not allowed.', | 'Multiple "abstract" modifiers are not allowed.')); | ||||
| 'abstract')); | |||||
| } | |||||
| if ($is_final) { | |||||
| $this->raiseLintAtNode( | |||||
| $modifier, | |||||
| pht( | |||||
| 'Cannot use the `%s` modifier on an `%s` class member', | |||||
| 'final', | |||||
| 'abstract')); | |||||
| } | } | ||||
| $abstract_modifier = $modifier; | |||||
| $is_abstract = true; | $is_abstract = true; | ||||
| break; | break; | ||||
| case 'final': | case 'final': | ||||
| if ($is_abstract) { | if ($is_property) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht( | pht( | ||||
| 'Cannot use the `%s` modifier on an `%s` class member', | 'Properties can not be declared "final".')); | ||||
| 'final', | |||||
| 'abstract')); | |||||
| } | } | ||||
| if ($is_final) { | if ($is_final) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht( | pht( | ||||
| 'Multiple `%s` modifiers are not allowed.', | 'Multiple "final" modifiers are not allowed.')); | ||||
| 'final')); | |||||
| } | } | ||||
| $final_modifier = $modifier; | |||||
| $is_final = true; | $is_final = true; | ||||
| break; | break; | ||||
| case 'public': | case 'public': | ||||
| case 'protected': | case 'protected': | ||||
| case 'private': | case 'private': | ||||
| if ($visibility) { | if ($visibility !== null) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht('Multiple access type modifiers are not allowed.')); | pht('Multiple access type modifiers are not allowed.')); | ||||
| } | } | ||||
| $visibility_modifier = $modifier; | |||||
| $visibility = $modifier->getConcreteString(); | $visibility = $modifier->getConcreteString(); | ||||
| $visibility = phutil_utf8_strtolower($visibility); | |||||
| break; | break; | ||||
| case 'static': | case 'static': | ||||
| if ($is_static) { | if ($is_static) { | ||||
| $this->raiseLintAtNode( | $this->raiseLintAtNode( | ||||
| $modifier, | $modifier, | ||||
| pht( | pht( | ||||
| 'Multiple `%s` modifiers are not allowed.', | 'Multiple "static" modifiers are not allowed.')); | ||||
| 'static')); | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| $is_private = ($visibility === 'private'); | |||||
| if ($is_final && $is_abstract) { | |||||
| if ($is_method) { | |||||
| $this->raiseLintAtNode( | |||||
| $final_modifier, | |||||
| pht('Methods may not be both "abstract" and "final".')); | |||||
| } else { | |||||
| // Properties can't be "abstract" and "final" either, but they can't | |||||
| // ever be "abstract" at all, and we've already raise a message about | |||||
| // that earlier. | |||||
| } | |||||
| } | |||||
| if ($is_private && $is_final) { | |||||
| if ($is_method) { | |||||
| $final_tokens = $final_modifier->getTokens(); | |||||
| $space_tokens = last($final_tokens)->getWhitespaceTokensAfter(); | |||||
| $final_offset = head($final_tokens)->getOffset(); | |||||
| $final_string = array_merge($final_tokens, $space_tokens); | |||||
| $final_string = mpull($final_string, 'getValue'); | |||||
| $final_string = implode('', $final_string); | |||||
| $this->raiseLintAtOffset( | |||||
| $final_offset, | |||||
| pht('Methods may not be both "private" and "final".'), | |||||
| $final_string, | |||||
| ''); | |||||
| } else { | |||||
| // Properties can't be "final" at all, and we already raised a | |||||
| // message about this. | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||