diff --git a/src/moduleutils/PhutilLibraryMapBuilder.php b/src/moduleutils/PhutilLibraryMapBuilder.php --- a/src/moduleutils/PhutilLibraryMapBuilder.php +++ b/src/moduleutils/PhutilLibraryMapBuilder.php @@ -332,11 +332,16 @@ 'xmap' => array(), ); + $type_translation = array( + 'interface' => 'class', + 'trait' => 'class', + ); + // Detect duplicate symbols within the library. foreach ($symbol_map as $file => $info) { foreach ($info['have'] as $type => $symbols) { foreach ($symbols as $symbol => $declaration) { - $lib_type = ($type == 'interface') ? 'class' : $type; + $lib_type = idx($type_translation, $type, $type); if (!empty($library_map[$lib_type][$symbol])) { $prior = $library_map[$lib_type][$symbol]; throw new Exception( diff --git a/src/symbols/PhutilSymbolLoader.php b/src/symbols/PhutilSymbolLoader.php --- a/src/symbols/PhutilSymbolLoader.php +++ b/src/symbols/PhutilSymbolLoader.php @@ -398,6 +398,12 @@ } + private static function classLikeExists($name) { + return class_exists($name, false) || + interface_exists($name, false) || + trait_exists($name, false); + } + /** * @task internal */ @@ -411,7 +417,7 @@ return; } } else { - if (class_exists($name, false) || interface_exists($name, false)) { + if (self::classLikeExists($name)) { return; } } @@ -431,7 +437,7 @@ $load_failed = pht('function'); } } else { - if (!class_exists($name, false) && !interface_exists($name, false)) { + if (!self::classLikeExists($name)) { $load_failed = pht('class or interface'); } } diff --git a/support/lib/extract-symbols.php b/support/lib/extract-symbols.php --- a/support/lib/extract-symbols.php +++ b/support/lib/extract-symbols.php @@ -112,18 +112,6 @@ $namespace, $path, pht('namespace `%s` statements', 'use')); } -$possible_traits = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); -foreach ($possible_traits as $possible_trait) { - $attributes = $possible_trait->getChildByIndex(0); - // Can't use getChildByIndex here because not all classes have attributes - foreach ($attributes->getChildren() as $attribute) { - if (strtolower($attribute->getConcreteString()) === 'trait') { - phutil_fail_on_unsupported_feature($possible_trait, $path, pht('traits')); - } - } -} - - // -( Marked Externals )------------------------------------------------------ @@ -256,17 +244,29 @@ // Find classes declared by this file. - // This is "class X ... { ... }". -$classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); -foreach ($classes as $class) { - $class_name = $class->getChildByIndex(1); - $have[] = array( - 'type' => 'class', +function build_have_element_for_class_declaration(XHPASTNode $class_node) { + $class_name = $class_node->getChildByIndex(1); + + $type = 'class'; + $attributes = $class_node->getChildByIndex(0); + foreach ($attributes->getChildren() as $attribute) { + if (strtolower($attribute->getConcreteString()) === 'trait') { + $type = 'trait'; + } + } + + return array( + 'type' => $type, 'symbol' => $class_name, ); } +$classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); +foreach ($classes as $class) { + $have[] = build_have_element_for_class_declaration($class); +} + // Find classes used by this file. We identify these: //