public function testStripUtilities() { // Variable stripping. $this->assertEqual('stuff', ArcanistXHPASTLintNamingHook::stripPHPVariable('stuff')); $this->assertEqual('stuff', ArcanistXHPASTLintNamingHook::stripPHPVariable('$stuff')); // Function/method stripping. $this->assertEqual('construct', ArcanistXHPASTLintNamingHook::stripPHPFunction('construct')); $this->assertEqual('construct', ArcanistXHPASTLintNamingHook::stripPHPFunction('__construct')); }
protected function lintNamingConventions($root) { // We're going to build up a list of <type, name, token, error> tuples // and then try to instantiate a hook class which has the opportunity to // override us. $names = array(); $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); foreach ($classes as $class) { $name_token = $class->getChildByIndex(1); $name_string = $name_token->getConcreteString(); $names[] = array('class', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isUpperCamelCase($name_string) ? null : 'Follow naming conventions: classes should be named using ' . 'UpperCamelCase.'); } $ifaces = $root->selectDescendantsOfType('n_INTERFACE_DECLARATION'); foreach ($ifaces as $iface) { $name_token = $iface->getChildByIndex(1); $name_string = $name_token->getConcreteString(); $names[] = array('interface', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isUpperCamelCase($name_string) ? null : 'Follow naming conventions: interfaces should be named using ' . 'UpperCamelCase.'); } $functions = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); foreach ($functions as $function) { $name_token = $function->getChildByIndex(2); if ($name_token->getTypeName() == 'n_EMPTY') { // Unnamed closure. continue; } $name_string = $name_token->getConcreteString(); $names[] = array('function', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isLowercaseWithUnderscores(ArcanistXHPASTLintNamingHook::stripPHPFunction($name_string)) ? null : 'Follow naming conventions: functions should be named using ' . 'lowercase_with_underscores.'); } $methods = $root->selectDescendantsOfType('n_METHOD_DECLARATION'); foreach ($methods as $method) { $name_token = $method->getChildByIndex(2); $name_string = $name_token->getConcreteString(); $names[] = array('method', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isLowerCamelCase(ArcanistXHPASTLintNamingHook::stripPHPFunction($name_string)) ? null : 'Follow naming conventions: methods should be named using ' . 'lowerCamelCase.'); } $param_tokens = array(); $params = $root->selectDescendantsOfType('n_DECLARATION_PARAMETER_LIST'); foreach ($params as $param_list) { foreach ($param_list->getChildren() as $param) { $name_token = $param->getChildByIndex(1); if ($name_token->getTypeName() == 'n_VARIABLE_REFERENCE') { $name_token = $name_token->getChildOfType(0, 'n_VARIABLE'); } $param_tokens[$name_token->getID()] = true; $name_string = $name_token->getConcreteString(); $names[] = array('parameter', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isLowercaseWithUnderscores(ArcanistXHPASTLintNamingHook::stripPHPVariable($name_string)) ? null : 'Follow naming conventions: parameters should be named using ' . 'lowercase_with_underscores.'); } } $constants = $root->selectDescendantsOfType('n_CLASS_CONSTANT_DECLARATION_LIST'); foreach ($constants as $constant_list) { foreach ($constant_list->getChildren() as $constant) { $name_token = $constant->getChildByIndex(0); $name_string = $name_token->getConcreteString(); $names[] = array('constant', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isUppercaseWithUnderscores($name_string) ? null : 'Follow naming conventions: class constants should be named ' . 'using UPPERCASE_WITH_UNDERSCORES.'); } } $member_tokens = array(); $props = $root->selectDescendantsOfType('n_CLASS_MEMBER_DECLARATION_LIST'); foreach ($props as $prop_list) { foreach ($prop_list->getChildren() as $token_id => $prop) { if ($prop->getTypeName() == 'n_CLASS_MEMBER_MODIFIER_LIST') { continue; } $name_token = $prop->getChildByIndex(0); $member_tokens[$name_token->getID()] = true; $name_string = $name_token->getConcreteString(); $names[] = array('member', $name_string, $name_token, ArcanistXHPASTLintNamingHook::isLowerCamelCase(ArcanistXHPASTLintNamingHook::stripPHPVariable($name_string)) ? null : 'Follow naming conventions: class properties should be named ' . 'using lowerCamelCase.'); } } $superglobal_map = array_fill_keys($this->getSuperGlobalNames(), true); $fdefs = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); $mdefs = $root->selectDescendantsOfType('n_METHOD_DECLARATION'); $defs = $fdefs->add($mdefs); foreach ($defs as $def) { $globals = $def->selectDescendantsOfType('n_GLOBAL_DECLARATION_LIST'); $globals = $globals->selectDescendantsOfType('n_VARIABLE'); $globals_map = array(); foreach ($globals as $global) { $global_string = $global->getConcreteString(); $globals_map[$global_string] = true; $names[] = array('global', $global_string, $global, null); } // Exclude access of static properties, since lint will be raised at // their declaration if they're invalid and they may not conform to // variable rules. This is slightly overbroad (includes the entire // rhs of a "Class::..." token) to cover cases like "Class:$x[0]". These // varaibles are simply made exempt from naming conventions. $exclude_tokens = array(); $statics = $def->selectDescendantsOfType('n_CLASS_STATIC_ACCESS'); foreach ($statics as $static) { $rhs = $static->getChildByIndex(1); $rhs_vars = $def->selectDescendantsOfType('n_VARIABLE'); foreach ($rhs_vars as $var) { $exclude_tokens[$var->getID()] = true; } } $vars = $def->selectDescendantsOfType('n_VARIABLE'); foreach ($vars as $token_id => $var) { if (isset($member_tokens[$token_id])) { continue; } if (isset($param_tokens[$token_id])) { continue; } if (isset($exclude_tokens[$token_id])) { continue; } $var_string = $var->getConcreteString(); // Awkward artifact of "$o->{$x}". $var_string = trim($var_string, '{}'); if (isset($superglobal_map[$var_string])) { continue; } if (isset($globals_map[$var_string])) { continue; } $names[] = array('variable', $var_string, $var, ArcanistXHPASTLintNamingHook::isLowercaseWithUnderscores(ArcanistXHPASTLintNamingHook::stripPHPVariable($var_string)) ? null : 'Follow naming conventions: variables should be named using ' . 'lowercase_with_underscores.'); } } $engine = $this->getEngine(); $working_copy = $engine->getWorkingCopy(); if ($working_copy) { // If a naming hook is configured, give it a chance to override the // default results for all the symbol names. $hook_class = $working_copy->getConfig('lint.xhpast.naminghook'); if ($hook_class) { $hook_obj = newv($hook_class, array()); foreach ($names as $k => $name_attrs) { list($type, $name, $token, $default) = $name_attrs; $result = $hook_obj->lintSymbolName($type, $name, $default); $names[$k][3] = $result; } } } // Raise anything we're left with. foreach ($names as $k => $name_attrs) { list($type, $name, $token, $result) = $name_attrs; if ($result) { $this->raiseLintAtNode($token, self::LINT_NAMING_CONVENTIONS, $result); } } }