mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 12:24:49 +01:00
Track references on global variables (#5122)
* Track references on global variables Add global type references to the type map, and fix up unused detection on global variables. * Add null assertions * PHPCS
This commit is contained in:
parent
6953658961
commit
417704ac23
@ -21,6 +21,7 @@ use Psalm\Internal\Analyzer\ProjectAnalyzer;
|
||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Block\ForeachAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\Fetch\ConstFetchAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\Fetch\VariableFetchAnalyzer;
|
||||
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
|
||||
use Psalm\Internal\Codebase\InternalCallMapHandler;
|
||||
use Psalm\Internal\Provider\ClassLikeStorageProvider;
|
||||
@ -1004,6 +1005,13 @@ class Codebase
|
||||
return '<?php ' . $function->getSignature(true);
|
||||
}
|
||||
|
||||
if (strpos($symbol, '$') === 0) {
|
||||
$type = VariableFetchAnalyzer::getGlobalType($symbol);
|
||||
if (!$type->isMixed()) {
|
||||
return '<?php ' . $type;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$storage = $this->classlike_storage_provider->get($symbol);
|
||||
return '<?php ' . ($storage->abstract ? 'abstract ' : '') . 'class ' . $storage->name;
|
||||
|
@ -165,6 +165,12 @@ class VariableFetchAnalyzer
|
||||
$context->vars_in_scope[$var_name] = clone $type;
|
||||
$context->vars_possibly_in_scope[$var_name] = true;
|
||||
|
||||
$codebase->analyzer->addNodeReference(
|
||||
$statements_analyzer->getFilePath(),
|
||||
$stmt,
|
||||
$var_name
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ use PhpParser;
|
||||
use Psalm\Internal\Analyzer\FunctionLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\Fetch\VariableFetchAnalyzer;
|
||||
use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Issue\InvalidGlobal;
|
||||
@ -56,6 +57,23 @@ class GlobalAnalyzer
|
||||
|
||||
$context->byref_constraints[$var_id] = new \Psalm\Internal\ReferenceConstraint();
|
||||
}
|
||||
$assignment_node = DataFlowNode::getForAssignment(
|
||||
$var_id,
|
||||
new CodeLocation($statements_analyzer, $var)
|
||||
);
|
||||
$context->vars_in_scope[$var_id]->parent_nodes = [
|
||||
$assignment_node->id => $assignment_node,
|
||||
];
|
||||
$statements_analyzer->registerVariable(
|
||||
$var_id,
|
||||
new CodeLocation($statements_analyzer, $var),
|
||||
$context->branch_point
|
||||
);
|
||||
$statements_analyzer->getCodebase()->analyzer->addNodeReference(
|
||||
$statements_analyzer->getFilePath(),
|
||||
$var,
|
||||
$var_id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase
|
||||
|
||||
public function testSimpleSymbolLookup(): void
|
||||
{
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
$config = $codebase->config;
|
||||
$config->globals['$my_global'] = 'string';
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
@ -68,7 +71,9 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase
|
||||
|
||||
function qux(int $a, int $b) : int {
|
||||
return $a + $b;
|
||||
}'
|
||||
}
|
||||
|
||||
$_SERVER;'
|
||||
);
|
||||
|
||||
new FileAnalyzer($this->project_analyzer, 'somefile.php', 'somefile.php');
|
||||
@ -83,7 +88,8 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase
|
||||
$this->assertSame('<?php BANANA', $codebase->getSymbolInformation('somefile.php', 'B\A::BANANA'));
|
||||
$this->assertSame("<?php function B\baz(\n int \$a\n) : int", $codebase->getSymbolInformation('somefile.php', 'B\baz()'));
|
||||
$this->assertSame("<?php function B\qux(\n int \$a,\n int \$b\n) : int", $codebase->getSymbolInformation('somefile.php', 'B\qux()'));
|
||||
$this->assertSame("<?php const B\APPLE string", $codebase->getSymbolInformation('somefile.php', 'B\APPLE'));
|
||||
$this->assertSame("<?php array<array-key, mixed>", $codebase->getSymbolInformation('somefile.php', '$_SERVER'));
|
||||
$this->assertSame("<?php string", $codebase->getSymbolInformation('somefile.php', '$my_global'));
|
||||
}
|
||||
|
||||
public function testSimpleSymbolLookupGlobalConst(): void
|
||||
@ -279,6 +285,36 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase
|
||||
$this->assertSame('B\A::foo()', $symbol_at_position[0]);
|
||||
}
|
||||
|
||||
public function testGetSymbolPositionGlobalVariable(): void
|
||||
{
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
$codebase->reportUnusedVariables();
|
||||
$config = $codebase->config;
|
||||
$config->throw_exception = false;
|
||||
$config->globals['$my_global'] = 'string';
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
function foo() : void {
|
||||
global $my_global;
|
||||
echo $my_global;
|
||||
}'
|
||||
);
|
||||
|
||||
$codebase->file_provider->openFile('somefile.php');
|
||||
$codebase->scanFiles();
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
|
||||
$symbol_at_position = $codebase->getReferenceAtPosition('somefile.php', new Position(2, 31));
|
||||
$this->assertNotNull($symbol_at_position);
|
||||
$this->assertSame('$my_global', $symbol_at_position[0]);
|
||||
|
||||
$symbol_at_position = $codebase->getReferenceAtPosition('somefile.php', new Position(3, 28));
|
||||
$this->assertNotNull($symbol_at_position);
|
||||
$this->assertSame('73-82:string', $symbol_at_position[0]);
|
||||
}
|
||||
|
||||
public function testGetSymbolPositionNullableArg(): void
|
||||
{
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
|
@ -3114,6 +3114,15 @@ class UnusedVariableTest extends TestCase
|
||||
};',
|
||||
'error_message' => 'UnusedVariable',
|
||||
],
|
||||
'globalVariableUsage' => [
|
||||
'<?php
|
||||
$a = "hello";
|
||||
function example() : void {
|
||||
global $a;
|
||||
}
|
||||
example();',
|
||||
'error_message' => 'UnusedVariable',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user