Add toLowerString() method to Name and Identifier

Avoids patterns like strtolower((string) $name) when using
strict types.
This commit is contained in:
Nikita Popov 2017-08-15 22:48:24 +02:00
parent 6ab69a7dc9
commit d97cc3d96e
6 changed files with 38 additions and 17 deletions

View File

@ -10,10 +10,10 @@ class NameContext {
/** @var null|Name Current namespace */
protected $namespace;
/** @var array Map of format [aliasType => [aliasName => originalName]] */
/** @var Name[][] Map of format [aliasType => [aliasName => originalName]] */
protected $aliases = [];
/** @var array Same as $aliases but preserving original case */
/** @var Name[][] Same as $aliases but preserving original case */
protected $origAliases = [];
/** @var ErrorHandler Error handler */
@ -101,7 +101,7 @@ class NameContext {
public function getResolvedName(Name $name, int $type) {
// don't resolve special class names
if ($type === Stmt\Use_::TYPE_NORMAL
&& in_array(strtolower($name->toString()), ['self', 'parent', 'static'])) {
&& in_array($name->toLowerString(), ['self', 'parent', 'static'])) {
if (!$name->isUnqualified()) {
$this->errorHandler->handleError(new Error(
sprintf("'\\%s' is an invalid class name", $name->toString()),
@ -177,7 +177,7 @@ class NameContext {
// Check for relevant namespace use statements
foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) {
$lcOrig = strtolower((string) $orig);
$lcOrig = $orig->toLowerString();
if (0 === strpos($lcName, $lcOrig . '\\')) {
$possibleNames[] = new Name($alias . substr($name, strlen($lcOrig)));
}
@ -192,7 +192,7 @@ class NameContext {
}
} else {
// Everything else is case-insensitive
if (strtolower((string) $orig) === $lcName) {
if ($orig->toLowerString() === $lcName) {
$possibleNames[] = new Name($alias);
}
}

View File

@ -27,10 +27,19 @@ class Identifier extends NodeAbstract
return ['name'];
}
/**
* Get lowercased identifier as string.
*
* @return string Lowercased identifier as string
*/
public function toLowerString() : string {
return strtolower($this->name);
}
/**
* Get identifier as string.
*
* @return string Identifier as string.
* @return string Identifier as string
*/
public function __toString() : string {
return $this->name;

View File

@ -100,6 +100,16 @@ class Name extends NodeAbstract
return $this->toString();
}
/**
* Returns lowercased string representation of the name, without taking the name type into
* account (e.g., no leading backslash for fully qualified names).
*
* @return string Lowercased string representation
*/
public function toLowerString() : string {
return strtolower(implode('\\', $this->parts));
}
/**
* Returns a string representation of the name by imploding the namespace parts with the
* namespace separator.

View File

@ -38,7 +38,7 @@ abstract class ClassLike extends Node\Stmt {
public function getMethod(string $name) {
$lowerName = strtolower($name);
foreach ($this->stmts as $stmt) {
if ($stmt instanceof ClassMethod && $lowerName === strtolower($stmt->name)) {
if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) {
return $stmt;
}
}

View File

@ -142,6 +142,6 @@ class ClassMethod extends Node\Stmt implements FunctionLike
* @return bool
*/
public function isMagic() : bool {
return isset(self::$magicNames[strtolower($this->name)]);
return isset(self::$magicNames[$this->name->toLowerString()]);
}
}

View File

@ -646,7 +646,7 @@ abstract class ParserAbstract implements Parser
return $name;
}
$lowerName = strtolower($name->toString());
$lowerName = $name->toLowerString();
if (!isset($scalarTypes[$lowerName])) {
return $name;
}
@ -730,7 +730,7 @@ abstract class ParserAbstract implements Parser
}
protected function checkNamespace(Namespace_ $node) {
if ($node->name && isset(self::$specialNames[strtolower($node->name)])) {
if ($node->name && isset(self::$specialNames[$node->name->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as namespace name', $node->name),
$node->name->getAttributes()
@ -749,14 +749,14 @@ abstract class ParserAbstract implements Parser
}
protected function checkClass(Class_ $node, $namePos) {
if (null !== $node->name && isset(self::$specialNames[strtolower($node->name)])) {
if (null !== $node->name && isset(self::$specialNames[$node->name->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name),
$this->getAttributesAt($namePos)
));
}
if ($node->extends && isset(self::$specialNames[strtolower($node->extends)])) {
if ($node->extends && isset(self::$specialNames[$node->extends->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends),
$node->extends->getAttributes()
@ -764,7 +764,7 @@ abstract class ParserAbstract implements Parser
}
foreach ($node->implements as $interface) {
if (isset(self::$specialNames[strtolower($interface)])) {
if (isset(self::$specialNames[$interface->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
$interface->getAttributes()
@ -774,7 +774,7 @@ abstract class ParserAbstract implements Parser
}
protected function checkInterface(Interface_ $node, $namePos) {
if (null !== $node->name && isset(self::$specialNames[strtolower($node->name)])) {
if (null !== $node->name && isset(self::$specialNames[$node->name->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name),
$this->getAttributesAt($namePos)
@ -782,7 +782,7 @@ abstract class ParserAbstract implements Parser
}
foreach ($node->extends as $interface) {
if (isset(self::$specialNames[strtolower($interface)])) {
if (isset(self::$specialNames[$interface->toLowerString()])) {
$this->emitError(new Error(
sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
$interface->getAttributes()
@ -793,7 +793,7 @@ abstract class ParserAbstract implements Parser
protected function checkClassMethod(ClassMethod $node, $modifierPos) {
if ($node->flags & Class_::MODIFIER_STATIC) {
switch (strtolower($node->name)) {
switch ($node->name->toLowerString()) {
case '__construct':
$this->emitError(new Error(
sprintf('Constructor %s() cannot be static', $node->name),
@ -844,7 +844,9 @@ abstract class ParserAbstract implements Parser
}
protected function checkUseUse(UseUse $node, $namePos) {
if ('self' === strtolower($node->alias) || 'parent' === strtolower($node->alias)) {
if ($node->alias &&
('self' === $node->alias->toLowerString() || 'parent' === $node->alias->toLowerString())
) {
$this->emitError(new Error(
sprintf(
'Cannot use %s as %s because \'%2$s\' is a special class name',