From 5336f4bcf0ba69b93dbd74057c9ace6efe50a60a Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Wed, 5 Jun 2013 11:41:39 -0700 Subject: [PATCH] Verify classes used in typehints Summary: Also support `SomeInterface::CONSTANT`. Test Plan: interface I { const A = 1; } I::A; function f(stdClass $a, array $b, Iterator $c) { } Linted Phabricator. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D6135 --- scripts/lib/PhutilLibraryMapBuilder.php | 2 +- scripts/phutil_symbols.php | 41 +++++++++++++------ .../linter/ArcanistPhutilLibraryLinter.php | 8 +++- 3 files changed, 35 insertions(+), 16 deletions(-) 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.