@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 127 lines 3.9 kB view raw
1#!/usr/bin/env php 2<?php 3 4$root = dirname(dirname(dirname(__FILE__))); 5require_once $root.'/scripts/__init_script__.php'; 6 7$args = new PhutilArgumentParser($argv); 8$args->setSynopsis(pht(<<<EOSYNOPSIS 9**generate_php_symbols.php** [__options__] 10 11 Generate repository symbols using XHPAST. Paths are read from stdin. 12EOSYNOPSIS 13 )); 14$args->parseStandardArguments(); 15 16if (posix_isatty(STDIN)) { 17 echo phutil_console_format( 18 "%s\n", 19 pht( 20 'Usage: %s', 21 "find . -type f -name '*.php' | ./generate_php_symbols.php")); 22 exit(1); 23} 24 25$input = file_get_contents('php://stdin'); 26$data = array(); 27$futures = array(); 28 29foreach (explode("\n", trim($input)) as $file) { 30 if (!phutil_nonempty_string($file)) { 31 continue; 32 } 33 34 $file = Filesystem::readablePath($file); 35 $data[$file] = Filesystem::readFile($file); 36 $futures[$file] = PhutilXHPASTBinary::getParserFuture($data[$file]); 37} 38 39$futures = new FutureIterator($futures); 40foreach ($futures->limit(8) as $file => $future) { 41 $tree = XHPASTTree::newFromDataAndResolvedExecFuture( 42 $data[$file], 43 $future->resolve()); 44 45 $root = $tree->getRootNode(); 46 $scopes = array(); 47 48 $functions = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); 49 foreach ($functions as $function) { 50 $name = $function->getChildByIndex(2); 51 // Skip anonymous functions. 52 if (!$name->getConcreteString()) { 53 continue; 54 } 55 print_symbol($file, 'function', $name); 56 } 57 58 $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); 59 foreach ($classes as $class) { 60 $class_name = $class->getChildByIndex(1); 61 print_symbol($file, 'class', $class_name); 62 $scopes[] = array($class, $class_name); 63 } 64 65 $interfaces = $root->selectDescendantsOfType('n_INTERFACE_DECLARATION'); 66 foreach ($interfaces as $interface) { 67 $interface_name = $interface->getChildByIndex(1); 68 // We don't differentiate classes and interfaces in highlighters. 69 print_symbol($file, 'class', $interface_name); 70 $scopes[] = array($interface, $interface_name); 71 } 72 73 $constants = $root->selectDescendantsOfType('n_CONSTANT_DECLARATION_LIST'); 74 foreach ($constants as $constant_list) { 75 foreach ($constant_list->getChildren() as $constant) { 76 $constant_name = $constant->getChildByIndex(0); 77 print_symbol($file, 'constant', $constant_name); 78 } 79 } 80 81 foreach ($scopes as $scope) { 82 // This prints duplicate symbols in the case of nested classes. 83 // Luckily, PHP doesn't allow those. 84 list($class, $class_name) = $scope; 85 86 $consts = $class->selectDescendantsOfType( 87 'n_CLASS_CONSTANT_DECLARATION_LIST'); 88 foreach ($consts as $const_list) { 89 foreach ($const_list->getChildren() as $const) { 90 $const_name = $const->getChildByIndex(0); 91 print_symbol($file, 'class_const', $const_name, $class_name); 92 } 93 } 94 95 $members = $class->selectDescendantsOfType( 96 'n_CLASS_MEMBER_DECLARATION_LIST'); 97 foreach ($members as $member_list) { 98 foreach ($member_list->getChildren() as $member) { 99 if ($member->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST') { 100 continue; 101 } 102 $member_name = $member->getChildByIndex(0); 103 print_symbol($file, 'member', $member_name, $class_name); 104 } 105 } 106 107 $methods = $class->selectDescendantsOfType('n_METHOD_DECLARATION'); 108 foreach ($methods as $method) { 109 $method_name = $method->getChildByIndex(2); 110 print_symbol($file, 'method', $method_name, $class_name); 111 } 112 } 113} 114 115function print_symbol($file, $type, XHPASTNode $node, $context = null) { 116 $parts = array( 117 $context ? $context->getConcreteString() : '', 118 // Variable tokens are `$name`, not just `name`, so strip the "$"" off of 119 // class field names 120 ltrim($node->getConcreteString(), '$'), 121 $type, 122 'php', 123 $node->getLineNumber(), 124 '/'.ltrim($file, './'), 125 ); 126 echo implode(' ', $parts)."\n"; 127}