Differential D21539 Diff 51274 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. | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } |