src/Migrations/IsRefinementMigration.hack (97 lines of code) (raw):

/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ namespace Facebook\HHAST; use namespace HH\Lib\{C, Str, Vec}; final class IsRefinementMigration extends BaseMigration { <<__Override>> public function migrateFile(string $_path, Script $ast): Script { $map = dict[ 'is_string' => () ==> new StringToken(null, null), 'is_int' => () ==> new IntToken(null, null), 'is_float' => () ==> new FloatToken(null, null), 'is_bool' => () ==> new BoolToken(null, null), 'is_resource' => () ==> new ResourceToken(null, null), 'is_vec' => () ==> new VectorTypeSpecifier( new VecToken(null, null), new LessThanToken(null, null), new SimpleTypeSpecifier(new NameToken(null, null, '_')), /* trailing comma */ null, new GreaterThanToken(null, null), ), 'is_keyset' => () ==> new KeysetTypeSpecifier( new KeysetToken(null, null), new LessThanToken(null, null), new SimpleTypeSpecifier(new NameToken(null, null, '_')), /* trailing comma */ null, new GreaterThanToken(null, null), ), 'is_dict' => () ==> new DictionaryTypeSpecifier( new DictToken(null, null), new LessThanToken(null, null), NodeList::createMaybeEmptyList(vec[ new ListItem( new SimpleTypeSpecifier(new NameToken(null, null, '_')), new CommaToken(null, new NodeList(vec[new WhiteSpace(' ')])), ), new ListItem( new SimpleTypeSpecifier(new NameToken(null, null, '_')), null, ), ]), new GreaterThanToken(null, null), ), ]; return $ast->rewriteDescendants(($node, $parents) ==> { if (!$node is FunctionCallExpression) { return $node; } $name = $node->getReceiver(); if ($name is NameToken) { $key = $name->getText(); } else if ($name is QualifiedName) { $key = $name->getParts()->getChildrenOfItems() |> Vec\map($$, $item ==> $item?->getText() ?? '') |> Str\join($$, '\\') |> Str\strip_prefix($$, '\\'); } else { return $node; } $make_replacement = $map[$key] ?? null; if ($make_replacement === null) { return $node; } $replacement = $make_replacement(); if (!$replacement is ITypeSpecifier) { $replacement = new SimpleTypeSpecifier($replacement); } $replacement = new IsExpression( $node->getArgumentListx()->getChildrenOfItems()[0], new IsToken( new NodeList(vec[new WhiteSpace(' ')]), new NodeList(vec[new WhiteSpace(' ')]), ), $replacement, ); $parent = C\lastx($parents); // Whitelist of cases where parenthese are not needed if ( ($parent is ListItem<_>) || ($parent is IfStatement) || ($parent is ParenthesizedExpression) ) { $first = $replacement->getFirstTokenx(); $last = $replacement->getLastTokenx(); return $replacement->replace( $first, $first->withLeading($node->getFirstTokenx()->getLeading()), ) ->replace( $last, $last->withTrailing($node->getLastTokenx()->getTrailing()), ); } return new ParenthesizedExpression( new LeftParenToken($node->getFirstTokenx()->getLeading(), null), $replacement, new RightParenToken(null, $node->getLastTokenx()->getTrailing()), ); }); } }