2018-01-21 18:44:46 +01:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Scanner;
|
|
|
|
|
|
|
|
use PhpParser;
|
|
|
|
use PhpParser\NodeTraverser;
|
2018-01-21 19:38:51 +01:00
|
|
|
use Psalm\Codebase;
|
2018-01-21 18:44:46 +01:00
|
|
|
use Psalm\FileSource;
|
|
|
|
use Psalm\Storage\FileStorage;
|
|
|
|
use Psalm\Visitor\DependencyFinderVisitor;
|
|
|
|
|
|
|
|
class FileScanner implements FileSource
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
public $file_path;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
public $file_name;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
public $will_analyze;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $file_path
|
|
|
|
* @param string $file_name
|
|
|
|
* @param bool $will_analyze
|
|
|
|
*/
|
|
|
|
public function __construct($file_path, $file_name, $will_analyze)
|
|
|
|
{
|
|
|
|
$this->file_path = $file_path;
|
|
|
|
$this->file_name = $file_name;
|
|
|
|
$this->will_analyze = $will_analyze;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param array<mixed, PhpParser\Node> $stmts
|
2018-02-19 06:27:39 +01:00
|
|
|
* @param bool $storage_from_cache
|
2018-02-19 17:53:30 +01:00
|
|
|
* @param bool $debug_output
|
2018-01-21 18:44:46 +01:00
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2018-02-19 17:53:30 +01:00
|
|
|
public function scan(
|
|
|
|
Codebase $codebase,
|
|
|
|
FileStorage $file_storage,
|
|
|
|
$storage_from_cache = false,
|
|
|
|
$debug_output = false
|
|
|
|
) {
|
2018-02-23 04:52:22 +01:00
|
|
|
if ((!$this->will_analyze || $file_storage->deep_scan)
|
|
|
|
&& $storage_from_cache
|
|
|
|
&& !$file_storage->has_trait
|
|
|
|
) {
|
2018-02-19 06:27:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-19 17:53:30 +01:00
|
|
|
$stmts = $codebase->statements_provider->getStatementsForFile(
|
|
|
|
$file_storage->file_path,
|
|
|
|
$debug_output
|
|
|
|
);
|
|
|
|
|
2018-05-23 05:38:27 +02:00
|
|
|
foreach ($stmts as $stmt) {
|
|
|
|
if (!$stmt instanceof PhpParser\Node\Stmt\ClassLike
|
|
|
|
&& !$stmt instanceof PhpParser\Node\Stmt\Function_
|
|
|
|
) {
|
|
|
|
$file_storage->has_extra_statements = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-19 17:53:30 +01:00
|
|
|
if ($debug_output) {
|
|
|
|
if ($this->will_analyze) {
|
2018-04-13 01:42:24 +02:00
|
|
|
echo 'Deep scanning ' . $file_storage->file_path . "\n";
|
2018-02-19 17:53:30 +01:00
|
|
|
} else {
|
2018-04-13 01:42:24 +02:00
|
|
|
echo 'Scanning ' . $file_storage->file_path . "\n";
|
2018-02-19 17:53:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-21 18:44:46 +01:00
|
|
|
$traverser = new NodeTraverser();
|
2018-02-23 04:52:22 +01:00
|
|
|
$traverser->addVisitor(new DependencyFinderVisitor($codebase, $file_storage, $this));
|
2018-01-21 18:44:46 +01:00
|
|
|
$traverser->traverse($stmts);
|
2018-02-21 19:54:11 +01:00
|
|
|
|
|
|
|
$file_storage->deep_scan = $this->will_analyze;
|
2018-01-21 18:44:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getFilePath()
|
|
|
|
{
|
|
|
|
return $this->file_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getFileName()
|
|
|
|
{
|
|
|
|
return $this->file_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getCheckedFilePath()
|
|
|
|
{
|
|
|
|
return $this->file_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getCheckedFileName()
|
|
|
|
{
|
|
|
|
return $this->file_name;
|
|
|
|
}
|
2018-02-23 21:39:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return \Psalm\Aliases
|
|
|
|
*/
|
|
|
|
public function getAliases()
|
|
|
|
{
|
|
|
|
return new \Psalm\Aliases();
|
|
|
|
}
|
2018-01-21 18:44:46 +01:00
|
|
|
}
|