PregMatchFlags.php 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. <?php declare(strict_types=1);
  2. namespace Composer\Pcre\PHPStan;
  3. use PHPStan\Analyser\Scope;
  4. use PHPStan\Type\ArrayType;
  5. use PHPStan\Type\Constant\ConstantArrayType;
  6. use PHPStan\Type\Constant\ConstantIntegerType;
  7. use PHPStan\Type\IntersectionType;
  8. use PHPStan\Type\TypeCombinator;
  9. use PHPStan\Type\Type;
  10. use PhpParser\Node\Arg;
  11. use PHPStan\Type\Php\RegexArrayShapeMatcher;
  12. use PHPStan\Type\TypeTraverser;
  13. use PHPStan\Type\UnionType;
  14. final class PregMatchFlags
  15. {
  16. static public function getType(?Arg $flagsArg, Scope $scope): ?Type
  17. {
  18. if ($flagsArg === null) {
  19. return new ConstantIntegerType(PREG_UNMATCHED_AS_NULL);
  20. }
  21. $flagsType = $scope->getType($flagsArg->value);
  22. $constantScalars = $flagsType->getConstantScalarValues();
  23. if ($constantScalars === []) {
  24. return null;
  25. }
  26. $internalFlagsTypes = [];
  27. foreach ($flagsType->getConstantScalarValues() as $constantScalarValue) {
  28. if (!is_int($constantScalarValue)) {
  29. return null;
  30. }
  31. $internalFlagsTypes[] = new ConstantIntegerType($constantScalarValue | PREG_UNMATCHED_AS_NULL);
  32. }
  33. return TypeCombinator::union(...$internalFlagsTypes);
  34. }
  35. static public function removeNullFromMatches(Type $matchesType): Type
  36. {
  37. return TypeTraverser::map($matchesType, static function (Type $type, callable $traverse): Type {
  38. if ($type instanceof UnionType || $type instanceof IntersectionType) {
  39. return $traverse($type);
  40. }
  41. if ($type instanceof ConstantArrayType) {
  42. return new ConstantArrayType(
  43. $type->getKeyTypes(),
  44. array_map(static function (Type $valueType) use ($traverse): Type {
  45. return $traverse($valueType);
  46. }, $type->getValueTypes()),
  47. $type->getNextAutoIndexes(),
  48. [],
  49. $type->isList()
  50. );
  51. }
  52. if ($type instanceof ArrayType) {
  53. return new ArrayType($type->getKeyType(), $traverse($type->getItemType()));
  54. }
  55. return TypeCombinator::removeNull($type);
  56. });
  57. }
  58. }