Dep: update

주로 PHAN
This commit is contained in:
2021-08-06 22:39:09 +09:00
parent 404cd24855
commit 21e7a4d966
1098 changed files with 92137 additions and 33228 deletions
+42 -19
View File
@@ -23,6 +23,7 @@ Shim::load();
*
* Configured stubs can be used in IDEs, analysis, etc. where extensions aren't installed or enabled (e.g. Xdebug)
* @phan-file-suppress PhanPluginDescriptionlessCommentOnPublicMethod, PhanPluginNoCommentOnPublicMethod
* @phan-file-suppress PhanPluginRemoveDebugAny
*/
class StubsGenerator
{
@@ -42,8 +43,15 @@ Usage: $prog_name [--opts]
-h, --help
Print this help message
-e, --extension
-e, --extension extension_name
Print stubs for only the given PECL or built in extension (e.g. 'ast', 'pcntl')
-d, --doc-comment
Include doc comments from the comment summaries bundled with Phan.
-o, --output path/to/file
Save the stubs to a file instead of printing them to stdout.
EOT;
exit($exit_code);
}
@@ -54,22 +62,33 @@ EOT;
*/
public static function main() : void
{
$options = getopt('he:', ['help', 'extension:']);
$options = getopt('he:o:d', ['help', 'extension:', 'output:', 'doc-comment']);
if (isset($options['h']) || isset($options['help'])) {
self::printHelpAndExit('', 0);
}
if (isset($options['d']) || isset($options['doc-comment'])) {
$_ENV['PHAN_STUB_INCLUDE_DOC'] = '1';
}
$code_base = require_once(dirname(__DIR__) . '/src/codebase.php');
$code_base = require(dirname(__DIR__) . '/src/codebase.php');
$extension_name = $options['e'] ?? $options['extension'] ?? null;
$output_path = $options['o'] ?? $options['output'] ?? null;
if (is_string($extension_name)) {
self::printStubsForExtension($extension_name, $code_base);
return;
$output = self::generateStubsForExtension($extension_name, $code_base);
} else {
$output = self::generateAllStubs($code_base);
}
if (is_string($output_path)) {
file_put_contents($output_path, $output);
fwrite(STDERR, "Saved stubs for $extension_name to $output_path\n");
} else {
echo $output;
}
self::printAllStubs($code_base);
}
private static function printStubsForExtension(string $extension_name, CodeBase $code_base) : void
private static function generateStubsForExtension(string $extension_name, CodeBase $code_base): string
{
$stub_collection = new StubCollection($code_base);
$reflection_extension = new ReflectionExtension($extension_name);
@@ -79,12 +98,14 @@ EOT;
self::recordGlobalFunctionStubsForExtension($stub_collection, $reflection_extension, $code_base);
self::recordGlobalConstantStubsForExtension($stub_collection, $reflection_extension, $code_base);
echo "<" . "?php\n";
echo "// These stubs were generated by the phan stub generator.\n";
echo "// @phan-stub-for-extension $extension_name@$extension_version\n";
echo "\n";
$result = '';
$result .= "<" . "?php\n";
$result .= "// These stubs were generated by the phan stub generator.\n";
$result .= "// @phan-stub-for-extension $extension_name@$extension_version\n";
$result .= "\n";
echo $stub_collection->toString();
$result .= $stub_collection->toString();
return $result;
}
private static function recordClassStubsForExtension(
@@ -150,14 +171,15 @@ EOT;
}
}
public static function printAllStubs(CodeBase $code_base) : void
public static function generateAllStubs(CodeBase $code_base): string
{
$code_base->eagerlyLoadAllSignatures();
$stub_collection = new StubCollection($code_base);
$class_map = $code_base->getInternalClassMap();
echo "<" . "?php\n";
echo "// These stubs were generated by the phan stub generator.\n";
$result = '';
$result .= "<" . "?php\n";
$result .= "// These stubs were generated by the phan stub generator.\n";
foreach ($class_map as $class) {
$stub_collection->addClazz($class);
@@ -176,7 +198,8 @@ EOT;
foreach ($const_map as $const) {
$stub_collection->addGlobalConstant($const);
}
echo $stub_collection->toString();
$result .= $stub_collection->toString();
return $result;
}
}
@@ -204,19 +227,19 @@ class StubCollection
public function addClazz(Clazz $class) : void
{
list($namespace, $name) = $class->toStubInfo($this->code_base);
[$namespace, $name] = $class->toStubInfo($this->code_base);
$this->class_stubs[$namespace][(string)$class->getFQSEN()] = $name;
}
public function addGlobalConstant(GlobalConstant $global_constant) : void
{
list($namespace, $name) = $global_constant->toStubInfo();
[$namespace, $name] = $global_constant->toStubInfo();
$this->global_constant_stubs[$namespace][(string)$global_constant->getFQSEN()] = $name;
}
public function addFunc(Func $function) : void
{
list($namespace, $name) = $function->toStubInfo();
[$namespace, $name] = $function->toStubInfo();
$this->function_stubs[$namespace][(string)$function->getFQSEN()] = $name;
}
+3 -2
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env php
<?php
// pdep is a tool to help explore dependencies of classes.
// @phan-file-suppress PhanPluginRemoveDebugEcho
use Phan\CLIBuilder;
use Phan\Phan;
@@ -113,7 +114,6 @@ call_user_func(static function () : void {
return;
}
$code_base = require_once __DIR__ . '/../src/codebase.php';
require_once __DIR__ . '/../src/Phan/Bootstrap.php';
$cli_builder = new CLIBuilder();
@@ -180,7 +180,6 @@ call_user_func(static function () : void {
$cwd = \getcwd();
// @phan-suppress-next-line PhanThrowTypeAbsentForCall
$cli_builder->setOption('allow-polyfill-parser');
$cli_builder->setOption('processes', '1');
$cli_builder->setOption('plugin', dirname($tool_dir) . '/src/Phan/Plugin/Internal/DependencyGraphPlugin.php');
@@ -196,6 +195,8 @@ call_user_func(static function () : void {
$putenv("PDEP_DEPTH", (string)$depth);
$putenv("PDEP_ARGS", $arg_string);
$putenv("PDEP_GRAPH_FLAGS", (string)$graph_flags);
// Generate codebase info after parsing configs (e.g. included_extension_subset)
$code_base = require(__DIR__ . '/../src/codebase.php');
if (isset($options['i'])) {
$data = @file_get_contents($graph_file);
+490
View File
@@ -0,0 +1,490 @@
<?php
declare(strict_types=1);
use Phan\CLI;
use Phan\Language\Element\Comment;
use Phan\Language\Element\MarkupDescription;
use Phan\Library\StringUtil;
// On the off chance that php or an extension ever provides a global function called 'help',
// check for this so that other utilities will work.
if (!function_exists('help')) {
/**
* tool/phan_repl_helpers.php is a utility that can be loaded after `php -a` is started.
*
* It provides the following:
* - A prototype replacement for PHP's code completion, on platforms where readline was installed.
* **This does not take advantage of Phan's inference and only reads the last line of multi-line expressions/statements.**
* - A prototype global function `help()` which will dump information about constants/functions/objects/classes.
*
* The format of this will probably change.
* - Access to an environment where Phan's bootstrapping and the project's autoloader already ran and Phan's classes can be autoloaded.
*
* Examples of how this can be loaded and used from a PHP shell:
*
* ```
* php > require_once 'tool/phan_repl_helpers.php';
*
* php > help(\Phan\CLI::class);
* Help for class Phan\CLI defined at /path/to/phan/src/Phan/CLI.php:79.
*
* Contains methods for parsing CLI arguments to Phan,
* outputting to the CLI, as well as helper methods to retrieve files/folders
* for the analyzed project.
*
* php > help('ast\AST_BINARY_OP');
* Help for global constant ast\AST_BINARY_OP
*
* Value: 520
*
* A binary operation of the form `left op right`.
* The operation is determined by the flags `ast\flags\BINARY_*`
* (children: left, right)
* ```
*
* tool/phan_repl_helpers.php also replaces the code completion capabilities
* of `php -a` with an alternative with a different feature set.
*
* ```
* php > require_once 'tool/phan_repl_helpers.php';
* php > $object = new ArrayObject();
* php > help($object);
* Help for class ArrayObject defined by module SPL.
*
* This class allows objects to work as arrays.
*
* php > $object->a<TAB>
* append asort
* ```
*
* @suppress PhanUnreferencedFunction this is meant to be used interactively and is currently untested
*/
function help($value = "\x00extended_help"): void
{
phan_repl_help($value);
}
} /* End function_exists('help') check */
/**
* Actual implementation of help()
*/
function phan_repl_help($value = "\x00extended_help"): void
{
if ($value === "\x00extended_help") {
echo "Phan " . CLI::PHAN_VERSION . " CLI autocompletion utilities.\n";
echo "Type help(\$value); or help('function or constant or class name'); for help.\n";
echo "Type help('help'); for extended help.\n";
return;
}
if ($value instanceof Closure || (is_string($value) && function_exists($value)) || $value instanceof ReflectionFunction) {
$reflection_function = $value instanceof ReflectionFunction ? $value : new ReflectionFunction($value);
$function_name = $reflection_function->getName();
$doc_comment = $reflection_function->getDocComment();
if ($reflection_function->isUserDefined()) {
$details = 'defined at ' . $reflection_function->getFileName() . ':' . $reflection_function->getStartLine();
} else {
$details = 'defined by module ' . $reflection_function->getExtensionName();
}
echo "Help for function $function_name $details.\n\n";
// TODO: Use Phan's stub generation code and handle any issues caused by inheritance?
// echo "$reflection_function\n";
$description = '';
if (is_string($doc_comment)) {
$description = MarkupDescription::extractDocComment($doc_comment, Comment::ON_FUNCTION);
}
if (strlen($description) > 0) {
echo rtrim($description) . "\n\n";
return;
}
$function_documentation = MarkupDescription::loadFunctionDescriptionMap()[strtolower($function_name)] ?? '';
if ($function_documentation !== '') {
echo rtrim($function_documentation) . "\n\n";
return;
}
echo "Could not find info on $function_name\n\n";
return;
}
if (is_object($value) || (is_string($value) && (class_exists($value) || trait_exists($value) || interface_exists($value)))) {
$class_name = is_string($value) ? $value : get_class($value);
$reflection_class = new ReflectionClass($class_name);
$class_name = ltrim($class_name, '\\');
if ($reflection_class->isUserDefined()) {
$details = 'defined at ' . $reflection_class->getFileName() . ':' . $reflection_class->getStartLine();
} else {
$details = 'defined by module ' . $reflection_class->getExtensionName();
}
echo "Help for class $class_name $details.\n\n";
$doc_comment = $reflection_class->getDocComment();
$description = '';
if (is_string($doc_comment)) {
$description = MarkupDescription::extractDocComment($doc_comment, Comment::ON_CLASS);
}
if (strlen($description) > 0) {
echo rtrim($description) . "\n\n";
return;
}
$class_documentation = MarkupDescription::loadClassDescriptionMap()[strtolower(ltrim($class_name, '\\'))] ?? '';
if ($class_documentation !== '') {
echo rtrim($class_documentation) . "\n\n";
return;
}
echo "Could not find info on $class_name\n\n";
return;
}
if (is_string($value) && defined($value)) {
// TODO: Make this properly case sensitive for names but not namespaces
// TODO: Support class constants
echo "Help for global constant $value\n\n";
echo "Value: " . StringUtil::jsonEncode(constant($value)) . "\n\n";
$constant_documentation = MarkupDescription::loadConstantDescriptionMap()[strtolower($value)] ?? '';
if ($constant_documentation !== '') {
echo rtrim($constant_documentation) . "\n\n";
return;
}
echo "Could not find info on $value\n\n";
return;
}
echo "Unknown value for help(). Value was:\n";
var_dump($value);
}
/**
* TODOs:
* - Take advantage of Phan's static analysis compatibilities for generating
* readline suggestions.
* Currently, this only reads the last 3 tokens and doesn't take advantage of Phan's inference.
* - Support help() for remaining element types
* - Look into alternative approaches
* - Look into ways to get the previous lines contents when the expression/statement to be evaluated contains newlines.
* - Integrate with other tools such as tool/phoogle to create a useful debugging environment
*/
// Currently used for signature info
require_once(__DIR__ . '/../src/Phan/Bootstrap.php');
// Phan's error handler terminates the process when there's an unexpected notice. This isn't helpful in an interactive shell.
restore_error_handler();
/**
* Utilities such as completions to be added to `php -a` after launching it.
*
* This is written as a class with public/protected methods to make it easier to extend or to unit test.
*
* TODO: When possible, take advantage of the code that already exists
* in Phan to generate completion for files, keywords, etc.
*
* TODO: Add unit tests
* @phan-file-suppress PhanPluginRemoveDebugAny this is a debugging utility
* @phan-file-suppress PhanAccessMethodInternal this is bundled with phan
*/
class PhanPhpShellUtils
{
/** @var bool whether to emit debugging code */
private $debug;
public function __construct(bool $debug = false)
{
$this->debug = $debug;
}
/**
* Append a line to a logging file
*/
public function appendToLogFile(string $line): void
{
if (!$this->debug) {
return;
}
@file_put_contents('/tmp/phan_repl_helpers.php', $line, FILE_APPEND);
}
/**
* Generate completions for the current token
*
* @param list<int|string> $candidates
* @return list<string>
*/
public function generateCompletionsFromCandidates(array $candidates, string $prefix, string $prefix_to_add_to_completion): array
{
$prefix_len = strlen($prefix);
$completions = [];
foreach ($candidates as $candidate) {
if (!is_string($candidate)) {
continue;
}
$candidate_len = strlen($candidate);
if ($candidate_len >= $prefix_len && strncmp($prefix, $candidate, $prefix_len) === 0) {
$completions[] = $prefix_to_add_to_completion . $candidate;
}
}
return $completions;
}
/**
* Generate completions for a variable. TODO: Account for local variables
* @return list<string>
*/
public function generateVariableCompletions(string $last_token_str): array
{
$prefix = ltrim($last_token_str, '${');
$keys = array_keys($GLOBALS);
$keys[] = 'GLOBALS';
$completions = self::generateCompletionsFromCandidates($keys, $prefix, '$');
$this->appendToLogFile("generateVariableCompletions for $last_token_str = " . StringUtil::jsonEncode($completions) . "\n");
return $completions;
}
/**
* Convert a token to a string
* @param array{0:int,1:string,2:int}|string|false $token
*/
public static function tokenToString($token): string
{
return is_array($token) ? $token[1] : (string)$token;
}
/**
* Generate completions for accessing instance property or methods where the object instance is known
*
* @return list<string>
* @suppress PhanCompatibleObjectTypePHP71
*/
public function generateCompletionsForInstancePropertyOfObject(object $object, string $instance_element_prefix): array
{
// Gets the accessible non-static properties of the given object according to scope.
$property_candidates = array_keys(get_object_vars($object));
$property_completions = self::generateCompletionsFromCandidates($property_candidates, $instance_element_prefix, '');
$reflection_object = new ReflectionClass($object);
$method_candidates = [];
foreach ($reflection_object->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$method_candidates[] = $method->getName(); // . '('; seems to cause extra whitespace to get added
}
$method_completions = self::generateCompletionsFromCandidates($method_candidates, $instance_element_prefix, '');
$completions = array_merge($property_completions, $method_completions);
if ($method_completions && !$property_completions) {
$this->setReadlineConfig('completion_append_character', "(");
}
$this->appendToLogFile("generateCompletionsForInstancePropertyOfObject completions = " . StringUtil::jsonEncode($completions) . "\n");
return $completions;
}
/**
* Generate completions for accessing instance property or methods ($obj->prefix)
*
* @param list<array{0:int,1:string,2:int}|string> $tokens
* @return list<string>
*/
public function generateInstanceObjectCompletions(array $tokens): array
{
$i = count($tokens) - 1;
$this->appendToLogFile("generateInstanceObjectCompletions tokens = " . StringUtil::jsonEncode($tokens) . "\n");
while (!is_array($tokens[$i]) || $tokens[$i][0] !== T_OBJECT_OPERATOR) {
$i--;
if ($i <= 0) {
return [];
}
}
$instance_element_prefix = self::tokenToString($tokens[$i + 1] ?? '');
// Not definitely the expression - tolerant-php-parser would be a better way to fetch this.
$expression = $tokens[$i - 1];
$expression_str = self::tokenToString($expression);
if (is_array($expression) && $expression[0] === T_VARIABLE) {
$var_name = substr($expression_str, 1);
$global_var = $GLOBALS[$var_name] ?? null;
if (!is_object($global_var)) {
return [];
}
return $this->generateCompletionsForInstancePropertyOfObject($global_var, $instance_element_prefix);
}
$this->appendToLogFile("instance_element_prefix = '$instance_element_prefix' expression=$expression_str\n");
return [];
}
/**
* Generate completions for SomeClass::$prefix or SomeClass::prefix
* @return list<string>
*/
public function generateStaticElementSuggestionsForClass(string $class, string $instance_element_prefix): array
{
// TODO support ::class
if (!class_exists($class)) {
return [];
}
$reflection_class = new ReflectionClass($class);
$property_completions = [];
if (($instance_element_prefix[0] ?? '$') === '$') {
// Generate completions for static properties
$property_candidates = [];
foreach ($reflection_class->getProperties(ReflectionProperty::IS_STATIC | ReflectionProperty::IS_PUBLIC) as $prop) {
$property_candidates[] = '$' . $prop->getName();
}
$property_completions = $this->generateCompletionsFromCandidates($property_candidates, $instance_element_prefix, '');
if ($instance_element_prefix !== '') {
return $property_completions;
}
}
// TODO: PHP adds filtering by ReflectionClassConstant::IS_PUBLIC in 8.0
// TODO: Make some of these case insensitive?
$constant_candidates = ['class'];
foreach ($reflection_class->getReflectionConstants() as $reflection_constant) {
if (!$reflection_constant->isPublic()) {
continue;
}
$constant_candidates[] = $reflection_constant->getName();
}
$constant_completions = $this->generateCompletionsFromCandidates($constant_candidates, $instance_element_prefix, '');
$method_candidates = [];
foreach ($reflection_class->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_STATIC) as $reflection_method) {
if (!$reflection_method->isPublic()) {
continue;
}
$method_candidates[] = $reflection_method->getName();
}
$method_completions = $this->generateCompletionsFromCandidates($method_candidates, $instance_element_prefix, '');
return array_merge(
$property_completions,
$constant_completions,
$method_completions
);
}
/**
* Generate completions for accessing class constants, static properties or methods ($obj::prefix)
*
* @param list<array{0:int,1:string,2:int}|string> $tokens
* @param string $completed_text this is the `Foo::prefix` that returned values need to begin with
* @return list<string>
*/
public function generateStaticObjectCompletions(array $tokens, string $completed_text): array
{
$i = count($tokens) - 1;
$this->appendToLogFile("generateStaticObjectCompletions tokens = " . StringUtil::jsonEncode($tokens) . "\n");
while (!is_array($tokens[$i]) || $tokens[$i][0] !== T_DOUBLE_COLON) {
$i--;
if ($i <= 0) {
return [];
}
}
$instance_element_prefix = self::tokenToString($tokens[$i + 1] ?? '');
// Not definitely the expression - tolerant-php-parser would be a better way to fetch this.
$expression = $tokens[$i - 1];
$expression_str = self::tokenToString($expression);
if (is_array($expression) && $expression[0] === T_STRING) {
// TODO: Check if this snippet is within a namespace block with uses, etc.
// Or just reuse Phan's real completion abilities.
$class_name = $expression[1];
$pos = strrpos($completed_text, '::');
if (!is_int($pos)) {
return [];
}
$new_prefix = substr($completed_text, 0, $pos + 2);
$completions = [];
foreach ($this->generateStaticElementSuggestionsForClass($class_name, $instance_element_prefix) as $element_name) {
$completions[] = $new_prefix . $element_name;
}
return $completions;
}
$this->appendToLogFile("instance_element_prefix = '$instance_element_prefix' expression=$expression_str\n");
return [];
}
/**
* @return list<string> a list of completions for a generic identifier
*/
public function generateCompletionsForGlobalName(string $prefix): array
{
$function_candidates = array_values(array_merge(...array_values(get_defined_functions(true))));
$function_completions = $this->generateCompletionsFromCandidates($function_candidates, $prefix, '');
// @phan-suppress-next-line PhanRedundantArrayValuesCall
$other_candidates = array_values(array_merge(
get_declared_classes(),
get_declared_traits(),
get_declared_interfaces(),
array_keys(get_defined_constants())
));
$other_completions = $this->generateCompletionsFromCandidates($other_candidates, $prefix, '');
if ($function_completions && !$other_completions) {
$this->setReadlineConfig('completion_append_character', "(");
}
$result = array_merge($function_completions, $other_completions);
$prefix_len = strlen($prefix);
foreach ($result as &$val) {
$i = strrpos(substr($val, 0, $prefix_len), '\\');
if ($i !== false) {
$val = substr($val, $i + 1);
}
}
return $result;
}
/**
* @param string|bool|int $value
*/
protected function setReadlineConfig(string $key, $value): void
{
readline_info($key, $value);
}
/** Workaround to make readline not print any suggestions. Not sure how if this will work on all versions. */
public const NO_AVAILABLE_COMPLETIONS = [''];
/**
* Generate completion for any token
* @return list<string>
*/
public function generateCompletions(string $text, int $start, int $end): array
{
$this->setReadlineConfig('completion_append_character', "\x00");
try {
// TODO: PHP's API only allows us to fetch the most recent line.
$line_buffer = readline_info('line_buffer');
$tokens = (@token_get_all('<' . '?php ' . $line_buffer)) ?: ['']; // Split up to fix vim syntax highlighting.
$last_token = end($tokens);
$last_token_str = self::tokenToString($last_token);
$this->appendToLogFile("text='''$text''' start=$start end=$end line_buffer='''$line_buffer''' last_token_str='''$last_token_str'''\n");
$c = $last_token_str[0] ?? '';
$prev_token = prev($tokens);
$prev_token_str = self::tokenToString($prev_token);
if ($last_token_str === '::' || $prev_token_str === '::') {
// Complete static members
// (Must check if this is completing a static property instead of a variable)
return $this->generateStaticObjectCompletions($tokens, $text) ?: self::NO_AVAILABLE_COMPLETIONS;
} elseif ($c === '$') {
return $this->generateVariableCompletions($last_token_str) ?: self::NO_AVAILABLE_COMPLETIONS;
} elseif ($last_token_str === '->' || $prev_token_str === '->') {
// TODO: Actually infer types for expressions other than variables
return $this->generateInstanceObjectCompletions($tokens) ?: self::NO_AVAILABLE_COMPLETIONS;
}
if ($last_token_str === '\\') {
if (is_array($prev_token)) {
$prev_token_kind = $prev_token[0];
// TODO: T_NAME_RELATIVE for namespace\
if ($prev_token_kind === T_STRING || PHP_VERSION_ID >= 80000 && in_array($prev_token_kind, [T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED], true)) {
$last_token_str = ltrim($prev_token[1], '\\') . $last_token_str;
}
}
}
// TODO: Handle completions when the text is incorrectly tokenized (e.g. 'ast\parse_')
// That would benefit from using tolerant-php-parser to identify identifiers that contain multiple tokens (e.g. `$x = ast\parse_<TAB>`)
// Alternately, just look for T_STRING and T_BACKSLASH and T_WHITESPACE combinations
return $this->generateCompletionsForGlobalName($last_token_str) ?: self::NO_AVAILABLE_COMPLETIONS;
// TODO: $c === '#' for ini completions for ini_set().
} catch (Throwable $e) {
$this->appendToLogFile("Caught $e");
}
return self::NO_AVAILABLE_COMPLETIONS;
}
}
if (function_exists('readline_completion_function')) {
readline_completion_function([new PhanPhpShellUtils(true), 'generateCompletions']);
} else {
echo __FILE__ . "could not install a readline_completion_function - the readline extension is unavailable\n";
}
+4 -4
View File
@@ -17,6 +17,8 @@
* - Add ways to integrate this with building a phar file (unsafe)
* - Integrate other optimizations Phan can already do, such as --automatic-fix for NotFullyQualifiedUsagePlugin.
* - Use Phan's signature map/documentation map information about which constants, classes, and functions/methods are internal
*
* @phan-file-suppress PhanPluginRemoveDebugAny
*/
use Phan\CLI;
@@ -74,16 +76,12 @@ call_user_func(static function () : void {
return;
}
$code_base = require_once(__DIR__ . '/../src/codebase.php');
require_once(__DIR__ . '/../src/Phan/Bootstrap.php');
$cli_builder = new CLIBuilder();
if ($has_any_option('p', 'progress-bar')) {
$cli_builder->setOption('progress-bar');
}
if ($has_any_option('p', 'progress-bar')) {
$cli_builder->setOption('progress-bar');
}
$cli_builder->setOption('force-polyfill-parser-with-original-tokens');
$cli_builder->setOption('plugin', dirname(__DIR__) . '/src/Phan/Plugin/Internal/PhantasmPlugin.php');
// @phan-suppress-next-line PhanThrowTypeAbsentForCall
@@ -113,6 +111,8 @@ call_user_func(static function () : void {
CLI::printErrorToStderr("Must either pass --output-directory <dir> or --in-place\n");
phantasm_usage(1);
}
// Generate codebase info after parsing configs (e.g. included_extension_subset)
$code_base = require(__DIR__ . '/../src/codebase.php');
// @phan-suppress-next-line PhanThrowTypeAbsentForCall
Phan::analyzeFileList($code_base, /** @return string[] */ static function () use($cli) : array {
+7 -2
View File
@@ -1,6 +1,10 @@
#!/usr/bin/env php
<?php
/** phoogle is a tool to locate functions based on their signatures. */
/**
* phoogle is a tool to locate functions based on their signatures.
*
* @phan-file-suppress PhanPluginRemoveDebugAny
*/
use Phan\CLIBuilder;
use Phan\Phan;
@@ -74,7 +78,6 @@ call_user_func(static function () : void {
phoogle_usage(1);
}
$code_base = require_once(__DIR__ . '/../src/codebase.php');
require_once(__DIR__ . '/../src/Phan/Bootstrap.php');
$cli_builder = new CLIBuilder();
@@ -95,6 +98,8 @@ call_user_func(static function () : void {
$cli_builder->setOption('find-signature', $remaining_argv[0]);
// @phan-suppress-next-line PhanThrowTypeAbsentForCall
$cli = $cli_builder->build();
// Generate codebase info after parsing configs (e.g. included_extension_subset)
$code_base = require(__DIR__ . '/../src/codebase.php');
// @phan-suppress-next-line PhanThrowTypeAbsentForCall
Phan::analyzeFileList($code_base, /** @return string[] */ static function () use($cli) : array {