Changeset View
Changeset View
Standalone View
Standalone View
support/lib/extract-symbols.php
| Show All 17 Lines | **extract-symbols.php** [__options__] __path.php__ | ||||
| class declarations are "have" symbols, while object instantiations | class declarations are "have" symbols, while object instantiations | ||||
| with "new X()" are "need" symbols. | with "new X()" are "need" symbols. | ||||
| Dependencies on builtins and symbols marked '@phutil-external-symbol' | Dependencies on builtins and symbols marked '@phutil-external-symbol' | ||||
| in docblocks are omitted without __--all__. | in docblocks are omitted without __--all__. | ||||
| Symbols are reported in JSON on stdout. | Symbols are reported in JSON on stdout. | ||||
| This script is used internally by libphutil/arcanist to build maps of | This script is used internally by Arcanist to build maps of library | ||||
| library symbols. | symbols. | ||||
| It would be nice to eventually implement this as a C++ xhpast binary, | It would be nice to eventually implement this as a C++ xhpast binary, | ||||
| as it's relatively stable and performance is currently awful | as it's relatively stable and performance is currently awful | ||||
| (500ms+ for moderately large files). | (500ms+ for moderately large files). | ||||
| EOHELP | EOHELP | ||||
| ); | ); | ||||
| $args->parseStandardArguments(); | $args->parseStandardArguments(); | ||||
| $args->parse( | $args->parse( | ||||
| array( | array( | ||||
| array( | array( | ||||
| 'name' => 'all', | 'name' => 'all', | ||||
| 'help' => pht( | 'help' => pht( | ||||
| 'Report all symbols, including built-ins and declared externals.'), | 'Emit all symbols, including built-ins and declared externals.'), | ||||
| ), | |||||
| array( | |||||
| 'name' => 'builtins', | |||||
| 'help' => pht('Emit builtin symbols.'), | |||||
| ), | ), | ||||
| array( | array( | ||||
| 'name' => 'ugly', | 'name' => 'ugly', | ||||
| 'help' => pht('Do not prettify JSON output.'), | 'help' => pht('Do not prettify JSON output.'), | ||||
| ), | ), | ||||
| array( | array( | ||||
| 'name' => 'path', | 'name' => 'path', | ||||
| 'wildcard' => true, | 'wildcard' => true, | ||||
| 'help' => pht('PHP Source file to analyze.'), | 'help' => pht('PHP Source file to analyze.'), | ||||
| ), | ), | ||||
| )); | )); | ||||
| $paths = $args->getArg('path'); | $paths = $args->getArg('path'); | ||||
| $show_all = $args->getArg('all'); | |||||
| $show_builtins = $args->getArg('builtins'); | |||||
| if ($show_all && $show_builtins) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Flags "--all" and "--builtins" are not compatible.')); | |||||
| } | |||||
| if ($show_builtins && $paths) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Flag "--builtins" may not be used with a path.')); | |||||
| } | |||||
| if ($show_builtins) { | |||||
| $path = '<builtins>'; | |||||
| $source_code = ''; | |||||
| } else { | |||||
| if (count($paths) !== 1) { | if (count($paths) !== 1) { | ||||
| throw new Exception(pht('Specify exactly one path!')); | throw new Exception(pht('Specify exactly one path!')); | ||||
| } | } | ||||
| $path = Filesystem::resolvePath(head($paths)); | $path = Filesystem::resolvePath(head($paths)); | ||||
| $show_all = $args->getArg('all'); | |||||
| $source_code = Filesystem::readFile($path); | $source_code = Filesystem::readFile($path); | ||||
| } | |||||
| try { | try { | ||||
| $tree = XHPASTTree::newFromData($source_code); | $tree = XHPASTTree::newFromData($source_code); | ||||
| } catch (XHPASTSyntaxErrorException $ex) { | } catch (XHPASTSyntaxErrorException $ex) { | ||||
| $result = array( | $result = array( | ||||
| 'error' => $ex->getMessage(), | 'error' => $ex->getMessage(), | ||||
| 'line' => $ex->getErrorLine(), | 'line' => $ex->getErrorLine(), | ||||
| 'file' => $path, | 'file' => $path, | ||||
| ▲ Show 20 Lines • Show All 398 Lines • ▼ Show 20 Lines | foreach ($need as $key => $spec) { | ||||
| if (!empty($required_symbols[$type][$name])) { | if (!empty($required_symbols[$type][$name])) { | ||||
| // Report only the first use of a symbol, since reporting all of them | // Report only the first use of a symbol, since reporting all of them | ||||
| // isn't terribly informative. | // isn't terribly informative. | ||||
| continue; | continue; | ||||
| } | } | ||||
| $required_symbols[$type][$name] = $spec['symbol']->getOffset(); | $required_symbols[$type][$name] = $spec['symbol']->getOffset(); | ||||
| } | } | ||||
| if ($show_builtins) { | |||||
| foreach ($builtins as $type => $builtin_symbols) { | |||||
| foreach ($builtin_symbols as $builtin_symbol => $ignored) { | |||||
| $declared_symbols[$type][$builtin_symbol] = null; | |||||
| } | |||||
| } | |||||
| } | |||||
| $result = array( | $result = array( | ||||
| 'have' => $declared_symbols, | 'have' => $declared_symbols, | ||||
| 'need' => $required_symbols, | 'need' => $required_symbols, | ||||
| 'xmap' => $xmap, | 'xmap' => $xmap, | ||||
| ); | ); | ||||
| // -( Output )---------------------------------------------------------------- | // -( Output )---------------------------------------------------------------- | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | function phutil_symbols_get_builtins() { | ||||
| } | } | ||||
| return array( | return array( | ||||
| 'class' => array_fill_keys($builtin['classes'], true) + array( | 'class' => array_fill_keys($builtin['classes'], true) + array( | ||||
| 'static' => true, | 'static' => true, | ||||
| 'parent' => true, | 'parent' => true, | ||||
| 'self' => true, | 'self' => true, | ||||
| 'PhutilBootloader' => true, | |||||
| // PHP7 defines these new parent classes of "Exception", but they do not | // PHP7 defines these new parent classes of "Exception", but they do not | ||||
| // exist prior to PHP7. It's possible to use them safely in PHP5, in | // exist prior to PHP7. It's possible to use them safely in PHP5, in | ||||
| // some cases, to write code which is compatible with either PHP5 or | // some cases, to write code which is compatible with either PHP5 or | ||||
| // PHP7, but it's hard for us tell if a particular use is safe or not. | // PHP7, but it's hard for us tell if a particular use is safe or not. | ||||
| // For now, assume users know what they're doing and that uses are safe. | // For now, assume users know what they're doing and that uses are safe. | ||||
| // For discussion, see T12855. | // For discussion, see T12855. | ||||
| 'Throwable' => true, | 'Throwable' => true, | ||||
| 'Error' => true, | 'Error' => true, | ||||
| Show All 9 Lines | 'class' => array_fill_keys($builtin['classes'], true) + array( | ||||
| 'void' => true, | 'void' => true, | ||||
| ), | ), | ||||
| 'function' => array_filter( | 'function' => array_filter( | ||||
| array( | array( | ||||
| 'empty' => true, | 'empty' => true, | ||||
| 'isset' => true, | 'isset' => true, | ||||
| 'die' => true, | 'die' => true, | ||||
| // These are provided by libphutil but not visible in the map. | |||||
| 'phutil_is_windows' => true, | |||||
| 'phutil_load_library' => true, | |||||
| 'phutil_is_hiphop_runtime' => true, | |||||
| // HPHP/i defines these functions as 'internal', but they are NOT | // HPHP/i defines these functions as 'internal', but they are NOT | ||||
| // builtins and do not exist in vanilla PHP. Make sure we don't mark | // builtins and do not exist in vanilla PHP. Make sure we don't mark | ||||
| // them as builtin since we need to add dependencies for them. | // them as builtin since we need to add dependencies for them. | ||||
| 'idx' => false, | 'idx' => false, | ||||
| 'id' => false, | 'id' => false, | ||||
| ) + array_fill_keys($builtin['functions'], true)), | ) + array_fill_keys($builtin['functions'], true)), | ||||
| 'interface' => array_fill_keys($builtin['interfaces'], true), | 'interface' => array_fill_keys($builtin['interfaces'], true), | ||||
| ); | ); | ||||
| } | } | ||||