1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00
psalm/tests/UnusedCodeTest.php

996 lines
30 KiB
PHP
Raw Normal View History

<?php
namespace Psalm\Tests;
use Psalm\Checker\FileChecker;
use Psalm\Config;
2017-07-25 23:04:58 +02:00
use Psalm\Context;
class UnusedCodeTest extends TestCase
{
/** @var \Psalm\Checker\ProjectChecker */
protected $project_checker;
/**
* @return void
*/
public function setUp()
{
FileChecker::clearCache();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->file_provider = new Provider\FakeFileProvider();
$this->project_checker = new \Psalm\Checker\ProjectChecker(
new TestConfig(),
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->file_provider,
2017-10-15 17:57:44 +02:00
new Provider\FakeParserCacheProvider()
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
);
2018-02-04 00:52:35 +01:00
$this->project_checker->getCodebase()->collectReferences();
}
/**
2017-07-25 23:04:58 +02:00
* @dataProvider providerFileCheckerValidCodeParse
*
* @param string $code
* @param array<string> $error_levels
*
* @return void
*/
public function testValidCode($code, array $error_levels = [])
2017-07-25 23:04:58 +02:00
{
$test_name = $this->getName();
if (strpos($test_name, 'PHP7-') !== false) {
if (version_compare(PHP_VERSION, '7.0.0dev', '<')) {
$this->markTestSkipped('Test case requires PHP 7.');
return;
}
} elseif (strpos($test_name, 'SKIPPED-') !== false) {
$this->markTestSkipped('Skipped due to a bug.');
}
$file_path = self::$src_dir_path . 'somefile.php';
2017-07-25 23:04:58 +02:00
$this->addFile(
$file_path,
2017-07-25 23:04:58 +02:00
$code
);
foreach ($error_levels as $error_level) {
$this->project_checker->config->setCustomErrorLevel($error_level, Config::REPORT_SUPPRESS);
}
$context = new Context();
$context->collect_references = true;
$this->analyzeFile($file_path, $context);
2018-02-04 00:52:35 +01:00
$this->project_checker->getCodebase()->classlikes->checkClassReferences();
2017-07-25 23:04:58 +02:00
}
/**
* @dataProvider providerFileCheckerInvalidCodeParse
2017-05-27 02:16:18 +02:00
*
* @param string $code
* @param string $error_message
* @param array<string> $error_levels
2017-05-27 02:16:18 +02:00
*
* @return void
*/
public function testInvalidCode($code, $error_message, $error_levels = [])
{
2017-07-25 23:04:58 +02:00
if (strpos($this->getName(), 'SKIPPED-') !== false) {
$this->markTestSkipped();
}
$this->expectException('\Psalm\Exception\CodeException');
$this->expectExceptionMessageRegexp('/\b' . preg_quote($error_message, '/') . '\b/');
$file_path = self::$src_dir_path . 'somefile.php';
foreach ($error_levels as $error_level) {
$this->project_checker->config->setCustomErrorLevel($error_level, Config::REPORT_SUPPRESS);
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->addFile(
$file_path,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$code
);
$context = new Context();
$context->collect_references = true;
$this->analyzeFile($file_path, $context);
2018-02-04 00:52:35 +01:00
$this->project_checker->getCodebase()->classlikes->checkClassReferences();
}
/**
* @return array
*/
public function providerFileCheckerValidCodeParse()
{
return [
'arrayOffset' => [
'<?php
/** @return void */
function foo() {
$a = 0;
$arr = ["hello"];
echo $arr[$a];
}',
],
'unset' => [
'<?php
/** @return void */
function foo() {
$a = 0;
$arr = ["hello"];
unset($arr[$a]);
2017-05-27 02:05:57 +02:00
}',
2017-07-25 23:04:58 +02:00
],
'usedVariables' => [
'<?php
/** @return string */
function foo() {
$a = 5;
$b = [];
$c[] = "hello";
$d = "Foo";
$e = "arg";
$f = new $d($e);
return $a . implode(",", $b) . $c[0] . get_class($f);
2017-07-25 23:04:58 +02:00
}',
'error_levels' => [
'PossiblyUndefinedVariable',
'MixedArrayAccess',
'MixedOperand',
'MixedAssignment',
],
2017-07-25 23:04:58 +02:00
],
'ifInFunctionWithReference' => [
2017-07-25 23:04:58 +02:00
'<?php
/** @return string */
function foo() {
$a = 5;
if (rand(0, 1)) {
$b = "hello";
} else {
$b = "goodbye";
}
return $a . $b;
}',
],
'byrefInForeachLoop' => [
'<?php
function foo(): void {
$a = [1, 2, 3];
foreach ($a as &$b) {
$b = $b + 1;
}
}',
],
'definedInSecondBranchOfCondition' => [
'<?php
function foo(): void {
if (rand(0, 1) && $a = rand(0, 1)) {
echo $a;
}
}',
],
'booleanOr' => [
'<?php
function foo(int $a, int $b): bool {
return $a || $b;
}',
2017-05-27 02:05:57 +02:00
],
'paramUsedInIf' => [
'<?php
function foo(string $a): void {
if (rand(0, 1)) {
echo $a;
}
}',
],
'magicCall' => [
'<?php
class A {
/** @var string */
private $value = "default";
/** @param string[] $args */
public function __call(string $name, array $args) {
if (count($args) == 1) {
$this->modify($name, $args[0]);
}
}
2018-01-11 21:50:45 +01:00
private function modify(string $name, string $value): void {
call_user_func(array($this, "modify_" . $name), $value);
}
2018-01-11 21:50:45 +01:00
public function modifyFoo(string $value): void {
$this->value = $value;
}
public function getFoo() : string {
return $this->value;
}
}
$m = new A();
$m->foo("value");
$m->modifyFoo("value2");
echo $m->getFoo();',
],
2017-12-29 17:26:28 +01:00
'usedTraitMethod' => [
'<?php
class A {
2018-01-11 21:50:45 +01:00
public function foo(): void {
2017-12-29 17:26:28 +01:00
echo "parent method";
}
}
trait T {
2018-01-11 21:50:45 +01:00
public function foo(): void {
2017-12-29 17:26:28 +01:00
echo "trait method";
}
}
class B extends A {
use T;
}
(new A)->foo();
(new B)->foo();',
],
'usedInterfaceMethod' => [
'<?php
interface I {
2018-01-11 21:50:45 +01:00
public function foo(): void;
}
class A implements I {
2018-01-11 21:50:45 +01:00
public function foo(): void {}
}
(new A)->foo();',
],
'dummyByRefVar' => [
'<?php
2018-01-11 21:50:45 +01:00
function foo(string &$a = null, string $b = null): void {
if ($a) {
echo $a;
}
if ($b) {
echo $b;
}
}
2018-01-11 21:50:45 +01:00
function bar(): void {
foo($dummy_byref_var, "hello");
}
bar();',
],
'foreachReassigned' => [
'<?php
function foo(): void {
$a = false;
foreach ([1, 2, 3] as $b) {
$a = true;
echo $b;
}
echo $a;
}',
],
'doWhileReassigned' => [
'<?php
function foo(): void {
$a = 5;
do {
echo $a;
$a = $a - rand(-3, 3);
} while ($a > 3);
}',
],
'whileTypeChangedInIfAndContinueWithReference' => [
'<?php
function foo(): void {
$a = false;
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = true;
continue;
}
$a = false;
}
echo $a;
}',
],
'whileReassignedInIfAndContinueWithReferenceAfter' => [
'<?php
function foo(): void {
$a = 5;
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = 7;
continue;
}
$a = 3;
}
echo $a;
}',
],
'whileReassignedInIfAndContinueWithReferenceBeforeAndAfter' => [
'<?php
function foo(): void {
$a = 5;
if ($a) {}
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = 7;
continue;
}
$a = 3;
}
echo $a;
}',
],
'whileReassigned' => [
'<?php
function foo(): void {
$a = false;
while(rand(0, 1)) {
$a = true;
}
echo $a;
}',
],
'ifVarReassignedInBranch' => [
'<?php
function foo(): void {
$a = true;
if (rand(0, 1)) {
$a = false;
}
if ($a) {
echo "cool";
}
}',
],
'elseVarReassignedInBranchAndReference' => [
'<?php
function foo(): void {
$a = false;
if (rand(0, 1)) {
// do nothing
} else {
$a = true;
//echo $a;
}
if ($a) {
echo "cool";
}
}',
],
'switchVarReassignedInBranch' => [
'<?php
function foo(): void {
$a = false;
switch (rand(0, 2)) {
case 0:
$a = true;
}
if ($a) {
echo "cool";
}
}',
],
'switchVarReassignedInBranchWithDefault' => [
'<?php
function foo(): void {
$a = false;
switch (rand(0, 2)) {
case 0:
$a = true;
break;
default:
$a = false;
}
if ($a) {
echo "cool";
}
}',
],
'throwWithMessageCall' => [
'<?php
function dangerous(): void {
throw new \Exception("bad");
}
function callDangerous(): void {
try {
dangerous();
} catch (Exception $e) {
echo $e->getMessage();
}
}',
],
'throwWithMessageCallAndAssignmentAndReference' => [
'<?php
function dangerous(): string {
if (rand(0, 1)) {
throw new \Exception("bad");
}
return "hello";
}
function callDangerous(): void {
$s = null;
try {
$s = dangerous();
} catch (Exception $e) {
echo $e->getMessage();
}
if ($s) {}
}',
],
'throwWithMessageCallAndAssignmentInCatchAndReference' => [
'<?php
function dangerous(): string {
if (rand(0, 1)) {
throw new \Exception("bad");
}
return "hello";
}
function callDangerous(): void {
$s = null;
try {
dangerous();
} catch (Exception $e) {
echo $e->getMessage();
$s = "hello";
}
if ($s) {}
}',
],
'throwWithMessageCallAndAssignmentInTryAndCatchAndReference' => [
'<?php
function dangerous(): string {
if (rand(0, 1)) {
throw new \Exception("bad");
}
return "hello";
}
function callDangerous(): void {
$s = null;
try {
$s = dangerous();
} catch (Exception $e) {
echo $e->getMessage();
$s = "hello";
}
if ($s) {}
}',
],
'throwWithMessageCallAndNestedAssignmentInTryAndCatchAndReference' => [
'<?php
function dangerous(): string {
if (rand(0, 1)) {
throw new \Exception("bad");
}
return "hello";
}
function callDangerous(): void {
$s = null;
if (rand(0, 1)) {
$s = "hello";
} else {
try {
$t = dangerous();
} catch (Exception $e) {
echo $e->getMessage();
$t = "hello";
}
if ($t) {
$s = $t;
}
}
if ($s) {}
}',
],
'ifInReturnBlock' => [
'<?php
function foo(): void {
$i = false;
foreach ([1, 2, 3] as $a) {
if (rand(0, 1)) {
$i = true;
}
echo $a;
}
if ($i) {}
}',
],
2018-01-29 00:13:38 +01:00
'unknownMethodCallWithVar' => [
'<?php
/** @psalm-suppress MixedMethodCall */
function passesByRef(object $a): void {
$a->passedByRef($b);
}',
],
'constructorIsUsed' => [
'<?php
class A {
public function __construct() {
$this->foo();
}
private function foo() : void {}
}
$a = new A();
echo (bool) $a;',
],
'everythingUsed' => [
'<?php
interface I {
public function foo();
}
class B implements I {
public function foo() : void {}
}
class A
{
/**
* @var I
*/
private $i;
/**
* @param int[] $as
*/
public function __construct(array $as) {
foreach ($as as $a) {
$this->a($a, 1);
}
$this->i = new B();
}
private function a(int $a, int $b): self
{
$this->v($a, $b);
$this->i->foo();
return $this;
}
private function v(int $a, int $b): void
{
if ($a + $b > 0) {
throw new \RuntimeException("");
}
}
}
new A([1, 2, 3]);',
],
'usedMethodCallVariable' => [
'<?php
function reindex(array $arr, string $methodName): array {
$ret = [];
foreach ($arr as $element) {
$ret[$element->$methodName()] = true;
}
return $ret;
}',
'error_levels' => [
'MixedAssignment',
'MixedMethodCall',
'MixedArrayOffset',
],
],
];
}
/**
* @return array
*/
public function providerFileCheckerInvalidCodeParse()
{
return [
'function' => [
'<?php
/** @return int */
function foo() {
$a = 5;
$b = [];
return $a;
}',
2017-05-27 02:05:57 +02:00
'error_message' => 'UnusedVariable',
],
'ifInFunctionWithoutReference' => [
'<?php
/** @return int */
function foo() {
$a = 5;
if (rand(0, 1)) {
$b = "hello";
} else {
$b = "goodbye";
}
return $a;
}',
2017-05-27 02:05:57 +02:00
'error_message' => 'UnusedVariable',
],
'varInNestedAssignmentWithoutReference' => [
'<?php
function foo(): void {
if (rand(0, 1)) {
$a = "foo";
}
}',
'error_message' => 'UnusedVariable',
],
'varInSecondNestedAssignmentWithoutReference' => [
'<?php
function foo(): void {
if (rand(0, 1)) {
$a = "foo";
echo $a;
}
if (rand(0, 1)) {
$a = "foo";
}
}',
'error_message' => 'UnusedVariable',
],
'varReassignedInBothBranchesOfIf' => [
'<?php
function foo(): void {
$a = "foo";
if (rand(0, 1)) {
$a = "bar";
} else {
$a = "bat";
}
echo $a;
}',
'error_message' => 'UnusedVariable',
],
'varReassignedInNestedBranchesOfIf' => [
'<?php
function foo(): void {
$a = "foo";
if (rand(0, 1)) {
if (rand(0, 1)) {
$a = "bar";
} else {
$a = "bat";
}
} else {
$a = "bang";
}
echo $a;
}',
'error_message' => 'UnusedVariable',
],
'ifVarReassignedInBranch' => [
'<?php
function foo(): void {
$a = true;
if (rand(0, 1)) {
$a = false;
}
}',
'error_message' => 'UnusedVariable',
],
'elseVarReassignedInBranchAndNoReference' => [
'<?php
function foo(): void {
$a = true;
if (rand(0, 1)) {
// do nothing
} else {
$a = false;
}
}',
'error_message' => 'UnusedVariable',
],
'switchVarReassignedInBranch' => [
'<?php
function foo(): void {
$a = false;
switch (rand(0, 2)) {
case 0:
$a = true;
}
}',
'error_message' => 'UnusedVariable',
],
'switchVarReassignedInBranchWithDefault' => [
'<?php
function foo(): void {
$a = false;
switch (rand(0, 2)) {
case 0:
$a = true;
break;
default:
$a = false;
}
}',
'error_message' => 'UnusedVariable',
],
'unusedListVar' => [
'<?php
function foo(): void {
list($a, $b) = explode(" ", "hello world");
echo $a;
}',
'error_message' => 'UnusedVariable',
],
'unusedPreForVar' => [
'<?php
function foo(): void {
$i = 0;
for ($i = 0; $i < 10; $i++) {
echo $i;
}
}',
'error_message' => 'UnusedVariable',
],
'unusedIfInReturnBlock' => [
'<?php
function foo(): void {
$i = rand(0, 1);
foreach ([1, 2, 3] as $a) {
if ($a % 2) {
$i = 7;
return;
}
}
if ($i) {}
}',
'error_message' => 'UnusedVariable',
],
'unusedIfVarInBranch' => [
'<?php
function foo(): void {
if (rand(0, 1)) {
} elseif (rand(0, 1)) {
if (rand(0, 1)) {
$a = "foo";
} else {
$a = "bar";
echo $a;
}
}
}',
'error_message' => 'UnusedVariable',
],
'throwWithMessageCallAndAssignmentAndNoReference' => [
'<?php
function dangerous(): string {
if (rand(0, 1)) {
throw new \Exception("bad");
}
return "hello";
}
function callDangerous(): void {
$s = null;
try {
$s = dangerous();
} catch (Exception $e) {
echo $e->getMessage();
}
}',
'error_message' => 'UnusedVariable',
],
'whileTypeChangedInIfWithoutReference' => [
'<?php
function foo(): void {
$a = false;
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = true;
}
}
}',
'error_message' => 'UnusedVariable',
],
'whileTypeChangedInIfAndContinueWithoutReference' => [
'<?php
function foo(): void {
$a = false;
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = true;
continue;
}
$a = false;
}
}',
'error_message' => 'UnusedVariable',
],
'whileReassignedInIfAndContinueWithoutReferenceAfter' => [
'<?php
function foo(): void {
$a = 5;
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = 7;
continue;
}
$a = 3;
}
}',
'error_message' => 'UnusedVariable',
],
'whileReassignedInIfAndContinueWithoutReference' => [
'<?php
function foo(): void {
$a = 3;
if ($a) {}
while (rand(0, 1)) {
if (rand(0, 1)) {
$a = 5;
continue;
}
$a = 3;
}
}',
'error_message' => 'UnusedVariable',
],
'unusedClass' => [
'<?php
class A { }',
2017-05-27 02:05:57 +02:00
'error_message' => 'UnusedClass',
],
'publicUnusedMethod' => [
'<?php
class A {
/** @return void */
public function foo() {}
}
new A();',
2017-05-27 02:05:57 +02:00
'error_message' => 'PossiblyUnusedMethod',
],
'possiblyUnusedParam' => [
'<?php
class A {
/** @return void */
public function foo(int $i) {}
}
(new A)->foo(4);',
'error_message' => 'PossiblyUnusedParam',
],
'unusedParam' => [
'<?php
function foo(int $i) {}
foo(4);',
'error_message' => 'UnusedParam',
],
'possiblyUnusedProperty' => [
'<?php
class A {
/** @var string */
public $foo = "hello";
}
$a = new A();',
'error_message' => 'PossiblyUnusedProperty',
'error_levels' => ['UnusedVariable'],
],
'unusedProperty' => [
'<?php
class A {
/** @var string */
private $foo = "hello";
}
$a = new A();',
'error_message' => 'UnusedProperty',
'error_levels' => ['UnusedVariable'],
],
'privateUnusedMethod' => [
'<?php
class A {
/** @return void */
private function foo() {}
}
new A();',
2017-05-27 02:05:57 +02:00
'error_message' => 'UnusedMethod',
],
2017-12-30 16:54:01 +01:00
'unevaluatedCode' => [
'<?php
2018-01-11 21:50:45 +01:00
function foo(): void {
2017-12-30 16:54:01 +01:00
return;
$a = "foo";
}',
'error_message' => 'UnevaluatedCode',
],
];
}
}