1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-25 16:22:42 +01:00

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
This commit is contained in:
Jakub Vrana 2013-06-05 11:41:39 -07:00
parent e93726cb3b
commit 5336f4bcf0
3 changed files with 35 additions and 16 deletions

View file

@ -21,7 +21,7 @@ final class PhutilLibraryMapBuilder {
const LIBRARY_MAP_VERSION = 2; const LIBRARY_MAP_VERSION = 2;
const SYMBOL_CACHE_VERSION_KEY = '__symbol_cache_version__'; const SYMBOL_CACHE_VERSION_KEY = '__symbol_cache_version__';
const SYMBOL_CACHE_VERSION = 8; const SYMBOL_CACHE_VERSION = 9;
/* -( Mapping libphutil Libraries )---------------------------------------- */ /* -( Mapping libphutil Libraries )---------------------------------------- */

View file

@ -211,10 +211,10 @@ foreach ($classes as $class) {
// - Static method call // - Static method call
// - Static property access // - Static property access
// - Use of class constant // - Use of class constant
// - typehints
// //
// TODO: Possibly support these: // TODO: Possibly support these:
// //
// - typehints
// - instanceof // - instanceof
// - catch // - catch
// - String literal in ReflectionClass(). // - String literal in ReflectionClass().
@ -273,11 +273,24 @@ foreach ($static_uses as $static_use) {
continue; continue;
} }
$need[] = array( $need[] = array(
'type' => 'class', 'type' => 'class/interface',
'symbol' => $name, '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 )------------------------------------------------------------ // -( Interfaces )------------------------------------------------------------
@ -355,14 +368,20 @@ foreach ($need as $key => $spec) {
} }
$type = $spec['type']; $type = $spec['type'];
foreach (explode('/', $type) as $libtype) {
if (!$show_all) { if (!$show_all) {
if (!empty($externals[$type][$name])) { if (!empty($externals[$libtype][$name])) {
// Ignore symbols declared as externals. // Ignore symbols declared as externals.
continue; continue 2;
} }
if (!empty($builtins[$type][$name])) { if (!empty($builtins[$libtype][$name])) {
// Ignore symbols declared as builtins. // Ignore symbols declared as builtins.
continue; continue 2;
}
}
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])) { if (!empty($required_symbols[$type][$name])) {
@ -370,10 +389,6 @@ foreach ($need as $key => $spec) {
// isn't terribly informative. // isn't terribly informative.
continue; 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(); $required_symbols[$type][$name] = $spec['symbol']->getOffset();
} }

View file

@ -134,14 +134,18 @@ final class ArcanistPhutilLibraryLinter extends ArcanistLinter {
} }
} }
$types = array('class', 'function', 'interface', 'class/interface');
foreach ($symbols as $library => $map) { foreach ($symbols as $library => $map) {
// Check for unknown symbols: uses of classes, functions or interfaces // Check for unknown symbols: uses of classes, functions or interfaces
// which are not defined anywhere. We reference the list of all symbols // which are not defined anywhere. We reference the list of all symbols
// we built up earlier. // we built up earlier.
foreach ($map as $file => $spec) { foreach ($map as $file => $spec) {
$need = idx($spec, 'need', array()); $need = idx($spec, 'need', array());
foreach (array('class', 'function', 'interface') as $type) { foreach ($types as $type) {
$libtype = ($type == 'interface') ? 'class' : $type; $libtype = $type;
if ($type == 'interface' || $type == 'class/interface') {
$libtype = 'class';
}
foreach (idx($need, $type, array()) as $symbol => $offset) { foreach (idx($need, $type, array()) as $symbol => $offset) {
if (!empty($all_symbols[$libtype][$symbol])) { if (!empty($all_symbols[$libtype][$symbol])) {
// Symbol is defined somewhere. // Symbol is defined somewhere.