From 69536589610ab70fd2011987b2eb640c32bf352b Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Thu, 28 Jan 2021 11:18:28 -0500 Subject: [PATCH] Add constant fetch to reference map (#5115) * Add constant fetch to reference map To support showing constant types on hover of constant references, we need to add them to the ref map. * Fix root constants * PHPCBF --- src/Psalm/Codebase.php | 36 +++++++++++++++++-- .../Expression/Fetch/ConstFetchAnalyzer.php | 19 ++++++++++ tests/LanguageServer/SymbolLookupTest.php | 21 +++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Codebase.php b/src/Psalm/Codebase.php index 6ad201368..74405aa63 100644 --- a/src/Psalm/Codebase.php +++ b/src/Psalm/Codebase.php @@ -18,7 +18,9 @@ use const PHP_MINOR_VERSION; use PhpParser; use function preg_match; 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\Type\Comparator\UnionTypeComparator; use Psalm\Internal\Codebase\InternalCallMapHandler; use Psalm\Internal\Provider\ClassLikeStorageProvider; @@ -39,6 +41,8 @@ use function strrpos; use function strtolower; use function substr; use function substr_count; +use function array_pop; +use function implode; class Codebase { @@ -1000,9 +1004,37 @@ class Codebase return 'getSignature(true); } - $storage = $this->classlike_storage_provider->get($symbol); + try { + $storage = $this->classlike_storage_provider->get($symbol); + return 'abstract ? 'abstract ' : '') . 'class ' . $storage->name; + } catch (\InvalidArgumentException $e) { + } - return 'abstract ? 'abstract ' : '') . 'class ' . $storage->name; + if (strpos($symbol, '\\')) { + $const_name_parts = explode('\\', $symbol); + $const_name = array_pop($const_name_parts); + $namespace_name = implode('\\', $const_name_parts); + + $namespace_constants = NamespaceAnalyzer::getConstantsForNamespace( + $namespace_name, + \ReflectionProperty::IS_PUBLIC + ); + if (isset($namespace_constants[$const_name])) { + $type = $namespace_constants[$const_name]; + return 'file_storage_provider->get($file_path); + if (isset($file_storage->constants[$symbol])) { + return 'constants[$symbol]; + } + $constant = ConstFetchAnalyzer::getGlobalConstType($this, $symbol, $symbol); + + if ($constant) { + return 'getMessage()); diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php index 9f729d048..a99e63a49 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Fetch/ConstFetchAnalyzer.php @@ -58,6 +58,25 @@ class ConstFetchAnalyzer $context ); + $codebase = $statements_analyzer->getCodebase(); + + $aliased_constants = $statements_analyzer->getAliases()->constants; + if (isset($aliased_constants[$const_name])) { + $fq_const_name = $aliased_constants[$const_name]; + } elseif ($stmt->name instanceof PhpParser\Node\Name\FullyQualified) { + $fq_const_name = $const_name; + } else { + $fq_const_name = Type::getFQCLNFromString($const_name, $statements_analyzer->getAliases()); + } + + $codebase->analyzer->addNodeReference( + $statements_analyzer->getFilePath(), + $stmt, + $const_type + ? $fq_const_name + : '*' . $fq_const_name + ); + if ($const_type) { $statements_analyzer->node_data->setType($stmt, clone $const_type); } elseif ($context->check_consts) { diff --git a/tests/LanguageServer/SymbolLookupTest.php b/tests/LanguageServer/SymbolLookupTest.php index a04d8e503..0d3e10e3a 100644 --- a/tests/LanguageServer/SymbolLookupTest.php +++ b/tests/LanguageServer/SymbolLookupTest.php @@ -44,6 +44,8 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase 'assertSame('getSymbolInformation('somefile.php', 'B\A::BANANA')); $this->assertSame("getSymbolInformation('somefile.php', 'B\baz()')); $this->assertSame("getSymbolInformation('somefile.php', 'B\qux()')); + $this->assertSame("getSymbolInformation('somefile.php', 'B\APPLE')); + } + + public function testSimpleSymbolLookupGlobalConst(): void + { + $this->addFile( + 'somefile.php', + 'project_analyzer, 'somefile.php', 'somefile.php'); + + $codebase = $this->project_analyzer->getCodebase(); + + $this->analyzeFile('somefile.php', new Context()); + $this->assertSame("getSymbolInformation('somefile.php', 'APPLE')); + $this->assertSame("getSymbolInformation('somefile.php', 'BANANA')); } public function testSimpleSymbolLocation(): void