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:
parent
b31e9c0cfe
commit
a10002adec
2 changed files with 101 additions and 31 deletions
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
src/lint/linter/__tests__/xhpast/php-compatibility.lint-test
Normal file
10
src/lint/linter/__tests__/xhpast/php-compatibility.lint-test
Normal 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"}}
|
Loading…
Reference in a new issue