diff --git a/scripts/lib/PhutilLibraryMapBuilder.php b/scripts/lib/PhutilLibraryMapBuilder.php index 861a9352..9dc35ac0 100755 --- a/scripts/lib/PhutilLibraryMapBuilder.php +++ b/scripts/lib/PhutilLibraryMapBuilder.php @@ -21,7 +21,7 @@ final class PhutilLibraryMapBuilder { const LIBRARY_MAP_VERSION = 2; const SYMBOL_CACHE_VERSION_KEY = '__symbol_cache_version__'; - const SYMBOL_CACHE_VERSION = 8; + const SYMBOL_CACHE_VERSION = 9; /* -( Mapping libphutil Libraries )---------------------------------------- */ diff --git a/scripts/phutil_symbols.php b/scripts/phutil_symbols.php index 50a342e8..6dc693ef 100755 --- a/scripts/phutil_symbols.php +++ b/scripts/phutil_symbols.php @@ -211,10 +211,10 @@ foreach ($classes as $class) { // - Static method call // - Static property access // - Use of class constant +// - typehints // // TODO: Possibly support these: // -// - typehints // - instanceof // - catch // - String literal in ReflectionClass(). @@ -273,11 +273,24 @@ foreach ($static_uses as $static_use) { continue; } $need[] = array( - 'type' => 'class', + 'type' => 'class/interface', 'symbol' => $name, ); } +// This is "function (X $x)". +$parameters = $root->selectDescendantsOfType('n_DECLARATION_PARAMETER'); +foreach ($parameters as $parameter) { + $hint = $parameter->getChildByIndex(0); + if ($hint->getTypeName() != 'n_CLASS_NAME') { + continue; + } + $need[] = array( + 'type' => 'class/interface', + 'symbol' => $hint, + ); +} + // -( Interfaces )------------------------------------------------------------ @@ -355,14 +368,20 @@ foreach ($need as $key => $spec) { } $type = $spec['type']; - if (!$show_all) { - if (!empty($externals[$type][$name])) { - // Ignore symbols declared as externals. - continue; + foreach (explode('/', $type) as $libtype) { + if (!$show_all) { + if (!empty($externals[$libtype][$name])) { + // Ignore symbols declared as externals. + continue 2; + } + if (!empty($builtins[$libtype][$name])) { + // Ignore symbols declared as builtins. + continue 2; + } } - if (!empty($builtins[$type][$name])) { - // Ignore symbols declared as builtins. - continue; + if (!empty($declared_symbols[$libtype][$name])) { + // We declare this symbol, so don't treat it as a requirement. + continue 2; } } if (!empty($required_symbols[$type][$name])) { @@ -370,10 +389,6 @@ foreach ($need as $key => $spec) { // isn't terribly informative. continue; } - if (!empty($declared_symbols[$type][$name])) { - // We declare this symbol, so don't treat it as a requirement. - continue; - } $required_symbols[$type][$name] = $spec['symbol']->getOffset(); } diff --git a/src/lint/linter/ArcanistPhutilLibraryLinter.php b/src/lint/linter/ArcanistPhutilLibraryLinter.php index 0a8f772e..5b695c18 100644 --- a/src/lint/linter/ArcanistPhutilLibraryLinter.php +++ b/src/lint/linter/ArcanistPhutilLibraryLinter.php @@ -134,14 +134,18 @@ final class ArcanistPhutilLibraryLinter extends ArcanistLinter { } } + $types = array('class', 'function', 'interface', 'class/interface'); foreach ($symbols as $library => $map) { // Check for unknown symbols: uses of classes, functions or interfaces // which are not defined anywhere. We reference the list of all symbols // we built up earlier. foreach ($map as $file => $spec) { $need = idx($spec, 'need', array()); - foreach (array('class', 'function', 'interface') as $type) { - $libtype = ($type == 'interface') ? 'class' : $type; + foreach ($types as $type) { + $libtype = $type; + if ($type == 'interface' || $type == 'class/interface') { + $libtype = 'class'; + } foreach (idx($need, $type, array()) as $symbol => $offset) { if (!empty($all_symbols[$libtype][$symbol])) { // Symbol is defined somewhere.