1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-26 00:32:41 +01:00

Raise a linter error when removed symbols are used

Summary: Ref T5141. Utilize the `'max'` key from the `php_compat_info.json` compatibility map to lint for the use of classes/functions/symbols which have been removed from the target PHP version.

Test Plan: Added a test case for `arc unit`.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: epriestley, Korvin

Maniphest Tasks: T5141

Differential Revision: https://secure.phabricator.com/D10538
This commit is contained in:
Joshua Spence 2015-01-04 18:38:07 +11:00
parent b31e9c0cfe
commit a10002adec
2 changed files with 101 additions and 31 deletions

View file

@ -201,7 +201,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
public function getVersion() { public function getVersion() {
// The version number should be incremented whenever a new rule is added. // The version number should be incremented whenever a new rule is added.
return '11'; return '12';
} }
protected function resolveFuture($path, Future $future) { protected function resolveFuture($path, Future $future) {
@ -451,27 +451,44 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
foreach ($calls as $call) { foreach ($calls as $call) {
$node = $call->getChildByIndex(0); $node = $call->getChildByIndex(0);
$name = $node->getConcreteString(); $name = $node->getConcreteString();
$version = idx($compat_info['functions'], $name);
if ($version && version_compare($version['min'], $this->version, '>')) { $version = idx($compat_info['functions'], $name, array());
// Check if whitelisted. $min = idx($version, 'min');
$whitelisted = false; $max = idx($version, 'max');
foreach (idx($whitelist['function'], $name, array()) as $range) {
if (array_intersect($range, array_keys($node->getTokens()))) { // Check if whitelisted.
$whitelisted = true; $whitelisted = false;
break; foreach (idx($whitelist['function'], $name, array()) as $range) {
} if (array_intersect($range, array_keys($node->getTokens()))) {
$whitelisted = true;
break;
} }
}
if ($whitelisted) { if ($whitelisted) {
continue; continue;
} }
if ($min && version_compare($min, $this->version, '>')) {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$node, $node,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->version}, but `{$name}()` was ". pht(
"not introduced until PHP {$version['min']}."); 'This codebase targets PHP %s, but `%s()` was not '.
'introduced until PHP %s.',
$this->version,
$name,
$min));
} else if ($max && version_compare($max, $this->version, '<')) {
$this->raiseLintAtNode(
$node,
self::LINT_PHP_COMPATIBILITY,
pht(
'This codebase targets PHP %s, but `%s()` was '.
'removed in PHP %s.',
$this->version,
$name,
$max));
} else if (array_key_exists($name, $compat_info['params'])) { } else if (array_key_exists($name, $compat_info['params'])) {
$params = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST'); $params = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST');
foreach (array_values($params->getChildren()) as $i => $param) { foreach (array_values($params->getChildren()) as $i => $param) {
@ -480,9 +497,13 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$param, $param,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->version}, but parameter ". pht(
($i + 1)." of `{$name}()` was not introduced until PHP ". 'This codebase targets PHP %s, but parameter %d '.
"{$version}."); 'of `%s()` was not introduced until PHP %s.',
$this->version,
$i + 1,
$name,
$version));
} }
} }
} }
@ -494,15 +515,21 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$node, $node,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->windowsVersion} on Windows, ". pht(
"but `{$name}()` is not available there."); 'This codebase targets PHP %s on Windows, '.
'but `%s()` is not available there.',
$this->windowsVersion,
$name));
} else if (version_compare($windows, $this->windowsVersion, '>')) { } else if (version_compare($windows, $this->windowsVersion, '>')) {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$node, $node,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->windowsVersion} on Windows, ". pht(
"but `{$name}()` is not available there until PHP ". 'This codebase targets PHP %s on Windows, '.
"{$this->windowsVersion}."); 'but `%s()` is not available there until PHP %s.',
$this->windowsVersion,
$name,
$windows));
} }
} }
} }
@ -510,9 +537,10 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
$classes = $root->selectDescendantsOfType('n_CLASS_NAME'); $classes = $root->selectDescendantsOfType('n_CLASS_NAME');
foreach ($classes as $node) { foreach ($classes as $node) {
$name = $node->getConcreteString(); $name = $node->getConcreteString();
$version = idx($compat_info['interfaces'], $name); $version = idx($compat_info['interfaces'], $name, array());
$version = idx($compat_info['classes'], $name, $version); $version = idx($compat_info['classes'], $name, $version);
if ($version && version_compare($version['min'], $this->version, '>')) { $min = idx($version, 'min');
$max = idx($version, 'max');
// Check if whitelisted. // Check if whitelisted.
$whitelisted = false; $whitelisted = false;
foreach (idx($whitelist['class'], $name, array()) as $range) { foreach (idx($whitelist['class'], $name, array()) as $range) {
@ -526,11 +554,26 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
continue; continue;
} }
if ($min && version_compare($min, $this->version, '>')) {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$node, $node,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->version}, but `{$name}` was not ". pht(
"introduced until PHP {$version['min']}."); 'This codebase targets PHP %s, but `%s` was not '.
'introduced until PHP %s.',
$this->version,
$name,
$min));
} else if ($max && version_compare($max, $this->version, '<')) {
$this->raiseLintAtNode(
$node,
self::LINT_PHP_COMPATIBILITY,
pht(
'This codebase targets PHP %s, but `%s` was '.
'removed in PHP %s.',
$this->version,
$name,
$max));
} }
} }
@ -540,13 +583,30 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
$constants = $root->selectDescendantsOfType('n_SYMBOL_NAME'); $constants = $root->selectDescendantsOfType('n_SYMBOL_NAME');
foreach ($constants as $node) { foreach ($constants as $node) {
$name = $node->getConcreteString(); $name = $node->getConcreteString();
$version = idx($compat_info['constants'], $name); $version = idx($compat_info['constants'], $name, array());
if ($version && version_compare($version['min'], $this->version, '>')) { $min = idx($version, 'min');
$max = idx($version, 'max');
if ($min && version_compare($min, $this->version, '>')) {
$this->raiseLintAtNode( $this->raiseLintAtNode(
$node, $node,
self::LINT_PHP_COMPATIBILITY, self::LINT_PHP_COMPATIBILITY,
"This codebase targets PHP {$this->version}, but `{$name}` was not ". pht(
"introduced until PHP {$version['min']}."); 'This codebase targets PHP %s, but `%s` was not '.
'introduced until PHP %s.',
$this->version,
$name,
$min));
} else if ($max && version_compare($max, $this->version, '<')) {
$this->raiseLintAtNode(
$node,
self::LINT_PHP_COMPATIBILITY,
pht(
'This codebase targets PHP %s, but `%s` was '.
'removed in PHP %s.',
$this->version,
$name,
$max));
} }
} }

View file

@ -0,0 +1,10 @@
<?php
define_syslog_variables();
var_dump(STREAM_ENFORCE_SAFE_MODE);
~~~~~~~~~~
error:3:1
error:4:10
~~~~~~~~~~
~~~~~~~~~~
{"config": {"xhpast.php-version": "5.4.0"}}