mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 09:37:59 +01:00
Add way to find all references to a given class or method in the codebase
This commit is contained in:
parent
bb7f8e320c
commit
d9433c9491
10
bin/psalm
10
bin/psalm
@ -24,7 +24,7 @@ $options = getopt(
|
|||||||
[
|
[
|
||||||
'help', 'debug', 'config:', 'monochrome', 'show-info:', 'diff',
|
'help', 'debug', 'config:', 'monochrome', 'show-info:', 'diff',
|
||||||
'file:', 'self-check', 'update-docblocks', 'output-format:',
|
'file:', 'self-check', 'update-docblocks', 'output-format:',
|
||||||
'find-dead-code', 'init',
|
'find-dead-code', 'init', 'find-references-to:',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -88,6 +88,9 @@ Options:
|
|||||||
--find-dead-code
|
--find-dead-code
|
||||||
Look for dead code
|
Look for dead code
|
||||||
|
|
||||||
|
--find-references-to=[class|method]
|
||||||
|
Searches the codebase for references to the given fully-qualified class or method,
|
||||||
|
where method is in the format class::methodName
|
||||||
|
|
||||||
HELP;
|
HELP;
|
||||||
|
|
||||||
@ -237,6 +240,8 @@ $is_diff = isset($options['diff']);
|
|||||||
|
|
||||||
$find_dead_code = isset($options['find-dead-code']);
|
$find_dead_code = isset($options['find-dead-code']);
|
||||||
|
|
||||||
|
$find_references_to = isset($options['find-references-to']) ? $options['find-references-to'] : null;
|
||||||
|
|
||||||
$update_docblocks = isset($options['update-docblocks']);
|
$update_docblocks = isset($options['update-docblocks']);
|
||||||
|
|
||||||
$project_checker = new ProjectChecker(
|
$project_checker = new ProjectChecker(
|
||||||
@ -245,7 +250,8 @@ $project_checker = new ProjectChecker(
|
|||||||
$output_format,
|
$output_format,
|
||||||
$debug,
|
$debug,
|
||||||
$update_docblocks,
|
$update_docblocks,
|
||||||
$find_dead_code
|
$find_dead_code || $find_references_to !== null,
|
||||||
|
$find_references_to
|
||||||
);
|
);
|
||||||
|
|
||||||
// initialise custom config, if passed
|
// initialise custom config, if passed
|
||||||
|
@ -407,7 +407,10 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($context->collect_references && $context->check_variables) {
|
if ($context->collect_references &&
|
||||||
|
!$this->getFileChecker()->project_checker->find_references_to &&
|
||||||
|
$context->check_variables
|
||||||
|
) {
|
||||||
foreach ($context->vars_possibly_in_scope as $var_name => $_) {
|
foreach ($context->vars_possibly_in_scope as $var_name => $_) {
|
||||||
if (strpos($var_name, '->') === false &&
|
if (strpos($var_name, '->') === false &&
|
||||||
$var_name !== '$this' &&
|
$var_name !== '$this' &&
|
||||||
|
@ -54,6 +54,11 @@ class ProjectChecker
|
|||||||
*/
|
*/
|
||||||
public $collect_references = false;
|
public $collect_references = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $find_references_to;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
@ -176,7 +181,8 @@ class ProjectChecker
|
|||||||
* @param boolean $debug_output
|
* @param boolean $debug_output
|
||||||
* @param string $output_format
|
* @param string $output_format
|
||||||
* @param bool $update_docblocks
|
* @param bool $update_docblocks
|
||||||
* @param bool $find_dead_code
|
* @param bool $collect_references
|
||||||
|
* @param string $find_references_to
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$use_color = true,
|
$use_color = true,
|
||||||
@ -184,13 +190,15 @@ class ProjectChecker
|
|||||||
$output_format = self::TYPE_CONSOLE,
|
$output_format = self::TYPE_CONSOLE,
|
||||||
$debug_output = false,
|
$debug_output = false,
|
||||||
$update_docblocks = false,
|
$update_docblocks = false,
|
||||||
$find_dead_code = false
|
$collect_references = false,
|
||||||
|
$find_references_to = null
|
||||||
) {
|
) {
|
||||||
$this->use_color = $use_color;
|
$this->use_color = $use_color;
|
||||||
$this->show_info = $show_info;
|
$this->show_info = $show_info;
|
||||||
$this->debug_output = $debug_output;
|
$this->debug_output = $debug_output;
|
||||||
$this->update_docblocks = $update_docblocks;
|
$this->update_docblocks = $update_docblocks;
|
||||||
$this->collect_references = $find_dead_code;
|
$this->collect_references = $collect_references;
|
||||||
|
$this->find_references_to = $find_references_to;
|
||||||
|
|
||||||
if (!in_array($output_format, [self::TYPE_CONSOLE, self::TYPE_JSON, self::TYPE_EMACS])) {
|
if (!in_array($output_format, [self::TYPE_CONSOLE, self::TYPE_JSON, self::TYPE_EMACS])) {
|
||||||
throw new \UnexpectedValueException('Unrecognised output format ' . $output_format);
|
throw new \UnexpectedValueException('Unrecognised output format ' . $output_format);
|
||||||
@ -279,7 +287,31 @@ class ProjectChecker
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->collect_references) {
|
if ($this->collect_references) {
|
||||||
$this->checkClassReferences();
|
if ($this->find_references_to) {
|
||||||
|
if (strpos($this->find_references_to, '::') !== false) {
|
||||||
|
$locations = $this->findReferencesToMethod($this->find_references_to);
|
||||||
|
} else {
|
||||||
|
$locations = $this->findReferencesToClassLike($this->find_references_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($locations as $location) {
|
||||||
|
$snippet = $location->getSnippet();
|
||||||
|
|
||||||
|
$snippet_bounds = $location->getSnippetBounds();
|
||||||
|
$selection_bounds = $location->getSelectionBounds();
|
||||||
|
|
||||||
|
$selection_start = $selection_bounds[0] - $snippet_bounds[0];
|
||||||
|
$selection_length = $selection_bounds[1] - $selection_bounds[0];
|
||||||
|
|
||||||
|
echo $location->file_name . ':' . $location->getLineNumber() . PHP_EOL .
|
||||||
|
($this->use_color
|
||||||
|
? substr($snippet, 0, $selection_start) .
|
||||||
|
"\e[97;42m" . substr($snippet, $selection_start, $selection_length) .
|
||||||
|
"\e[0m" . substr($snippet, $selection_length + $selection_start)
|
||||||
|
: $snippet
|
||||||
|
) . PHP_EOL . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IssueBuffer::finish(true, (int)$start_checks, $this->visited_files);
|
IssueBuffer::finish(true, (int)$start_checks, $this->visited_files);
|
||||||
@ -325,6 +357,52 @@ class ProjectChecker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $method_id
|
||||||
|
* @return \Psalm\CodeLocation[]
|
||||||
|
*/
|
||||||
|
public function findReferencesToMethod($method_id)
|
||||||
|
{
|
||||||
|
list($fq_class_name, $method_name) = explode('::', $method_id);
|
||||||
|
|
||||||
|
if (!isset(ClassLikeChecker::$storage[strtolower($fq_class_name)])) {
|
||||||
|
die('Class ' . $fq_class_name . ' cannot be found' . PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
$class_storage = ClassLikeChecker::$storage[strtolower($fq_class_name)];
|
||||||
|
|
||||||
|
if (!isset($class_storage->methods[strtolower($method_name)])) {
|
||||||
|
die('Method ' . $method_id . ' cannot be found' . PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
$method_storage = $class_storage->methods[strtolower($method_name)];
|
||||||
|
|
||||||
|
if ($method_storage->referencing_locations === null) {
|
||||||
|
die('No references found for ' . $method_id . PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $method_storage->referencing_locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $fq_class_name
|
||||||
|
* @return \Psalm\CodeLocation[]
|
||||||
|
*/
|
||||||
|
public function findReferencesToClassLike($fq_class_name)
|
||||||
|
{
|
||||||
|
if (!isset(ClassLikeChecker::$storage[strtolower($fq_class_name)])) {
|
||||||
|
die('Class ' . $fq_class_name . ' cannot be found' . PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
$class_storage = ClassLikeChecker::$storage[strtolower($fq_class_name)];
|
||||||
|
|
||||||
|
if ($class_storage->referencing_locations === null) {
|
||||||
|
die('No references found for ' . $fq_class_name . PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $class_storage->referencing_locations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
@ -697,12 +697,16 @@ class CallChecker
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($var_id === '$this') {
|
||||||
|
$does_class_exist = true;
|
||||||
|
} else {
|
||||||
$does_class_exist = ClassLikeChecker::checkFullyQualifiedClassLikeName(
|
$does_class_exist = ClassLikeChecker::checkFullyQualifiedClassLikeName(
|
||||||
$fq_class_name,
|
$fq_class_name,
|
||||||
$statements_checker->getFileChecker(),
|
$statements_checker->getFileChecker(),
|
||||||
new CodeLocation($statements_checker->getSource(), $stmt->var),
|
new CodeLocation($statements_checker->getSource(), $stmt->var),
|
||||||
$statements_checker->getSuppressedIssues()
|
$statements_checker->getSuppressedIssues()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$does_class_exist) {
|
if (!$does_class_exist) {
|
||||||
return $does_class_exist;
|
return $does_class_exist;
|
||||||
|
Loading…
Reference in New Issue
Block a user