1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-22 21:40:54 +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 SYMBOL_CACHE_VERSION_KEY = '__symbol_cache_version__';
const SYMBOL_CACHE_VERSION = 8;
const SYMBOL_CACHE_VERSION = 9;
/* -( Mapping libphutil Libraries )---------------------------------------- */

View file

@ -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();
}

View file

@ -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.