fromCode() public static method

Create token collection directly from code.
public static fromCode ( string $code ) : Tokens
$code string PHP code
return Tokens
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $uses = array_reverse($tokensAnalyzer->getImportUseIndexes());
     foreach ($uses as $index) {
         $endIndex = $tokens->getNextTokenOfKind($index, array(';'));
         $declarationContent = $tokens->generatePartialCode($index + 1, $endIndex - 1);
         $declarationParts = explode(',', $declarationContent);
         if (1 === count($declarationParts)) {
             continue;
         }
         $declarationContent = array();
         foreach ($declarationParts as $declarationPart) {
             $declarationContent[] = 'use ' . trim($declarationPart) . ';';
         }
         $declarationContent = implode("\n" . $this->detectIndent($tokens, $index), $declarationContent);
         for ($i = $index; $i <= $endIndex; ++$i) {
             $tokens[$i]->clear();
         }
         $declarationTokens = Tokens::fromCode('<?php ' . $declarationContent);
         $declarationTokens[0]->clear();
         $declarationTokens->clearEmptyTokens();
         $tokens->insertAt($index, $declarationTokens);
     }
 }
Esempio n. 2
0
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
     $usesOrder = array();
     if (!count($namespacesImports)) {
         return;
     }
     foreach ($namespacesImports as $uses) {
         $uses = array_reverse($uses);
         $usesOrder = array_replace($usesOrder, $this->getNewOrder($uses, $tokens));
     }
     $usesOrder = array_reverse($usesOrder, true);
     $mapStartToEnd = array();
     foreach ($usesOrder as $use) {
         $mapStartToEnd[$use[1]] = $use[2];
     }
     // Now insert the new tokens, starting from the end
     foreach ($usesOrder as $index => $use) {
         $declarationTokens = Tokens::fromCode('<?php use ' . $use[0] . ';');
         $declarationTokens->clearRange(0, 2);
         // clear `<?php use `
         $declarationTokens[count($declarationTokens) - 1]->clear();
         // clear `;`
         $declarationTokens->clearEmptyTokens();
         $tokens->overrideRange($index, $mapStartToEnd[$index], $declarationTokens);
     }
 }
 /**
  * @dataProvider provideProcessCases
  */
 public function testProcess($source, array $expectedTokens)
 {
     $tokens = Tokens::fromCode($source);
     foreach ($expectedTokens as $index => $expectedToken) {
         $token = $tokens[$index];
         $this->assertSame($expectedToken[1], $token->getContent());
         $this->assertSame($expectedToken[0], $token->getId());
     }
 }
Esempio n. 4
0
 /**
  * {@inheritdoc}
  */
 public function lintSource($source)
 {
     try {
         // it will throw ParseError on syntax error
         // if not, it will cache the tokenized version of code, which is great for Runner
         Tokens::fromCode($source);
         return new TokenizerLintingResult();
     } catch (\ParseError $e) {
         return new TokenizerLintingResult($e);
     }
 }
 protected function doTest($source, array $expectedTokens = array(), array $observedKinds = array())
 {
     $tokens = Tokens::fromCode($source);
     $this->assertSame(count($expectedTokens), array_sum(array_map(function ($item) {
         return count($item);
     }, $tokens->findGivenKind(array_unique(array_merge($observedKinds, array_values($expectedTokens)))))));
     foreach ($expectedTokens as $index => $tokenId) {
         $this->assertSame(CT::has($tokenId) ? CT::getName($tokenId) : token_name($tokenId), $tokens[$index]->getName(), sprintf('Token kind should be the same at index %d.', $index));
         $this->assertSame($tokenId, $tokens[$index]->getId());
     }
 }
Esempio n. 6
0
 /**
  * @param int    $expected
  * @param string $code
  * @param int    $index
  *
  * @dataProvider provideCommentBlockStartDetectionCases
  */
 public function testCommentBlockStartDetection($expected, $code, $index)
 {
     Tokens::clearCache();
     $tokens = Tokens::fromCode($code);
     $fixer = $this->getFixer();
     $method = new \ReflectionMethod($fixer, 'findCommentBlockStart');
     $method->setAccessible(true);
     if ($expected !== ($result = $method->invoke($fixer, $tokens, $index))) {
         $this->fail(sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson()));
     }
 }
 protected function doTest($source, array $expectedTokens = array())
 {
     $tokens = Tokens::fromCode($source);
     $this->assertSame(count($expectedTokens), array_sum(array_map(function ($item) {
         return count($item);
     }, $tokens->findGivenKind(array_map(function ($name) {
         return constant($name);
     }, $expectedTokens)))));
     foreach ($expectedTokens as $index => $name) {
         $this->assertSame($name, $tokens[$index]->getName());
         $this->assertSame(constant($name), $tokens[$index]->getId());
     }
 }
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokensOrg)
 {
     $content = $tokensOrg->generateCode();
     // replace all <? with <?php to replace all short open tags even without short_open_tag option enabled
     $newContent = preg_replace('/<\\?(\\s|$)/', '<?php$1', $content, -1, $count);
     if (!$count) {
         return;
     }
     /* the following code is magic to revert previous replacements which should NOT be replaced, for example incorrectly replacing
      * > echo '<? ';
      * with
      * > echo '<?php ';
      */
     $tokens = Tokens::fromCode($newContent);
     $tokensOldContent = '';
     $tokensOldContentLength = 0;
     foreach ($tokens as $token) {
         if ($token->isGivenKind(T_OPEN_TAG)) {
             $tokenContent = $token->getContent();
             if ('<?php' !== substr($content, $tokensOldContentLength, 5)) {
                 $tokenContent = '<? ';
             }
             $tokensOldContent .= $tokenContent;
             $tokensOldContentLength += strlen($tokenContent);
             continue;
         }
         if ($token->isGivenKind(array(T_COMMENT, T_DOC_COMMENT, T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, T_STRING))) {
             $tokenContent = '';
             $tokenContentLength = 0;
             $parts = explode('<?php', $token->getContent());
             $iLast = count($parts) - 1;
             foreach ($parts as $i => $part) {
                 $tokenContent .= $part;
                 $tokenContentLength += strlen($part);
                 if ($i !== $iLast) {
                     if ('<?php' === substr($content, $tokensOldContentLength + $tokenContentLength, 5)) {
                         $tokenContent .= '<?php';
                         $tokenContentLength += 5;
                     } else {
                         $tokenContent .= '<?';
                         $tokenContentLength += 2;
                     }
                 }
             }
             $token->setContent($tokenContent);
         }
         $tokensOldContent .= $token->getContent();
         $tokensOldContentLength += strlen($token->getContent());
     }
     $tokensOrg->overrideRange(0, $tokensOrg->count() - 1, $tokens);
 }
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $uses = array_reverse($tokensAnalyzer->getImportUseIndexes());
     foreach ($uses as $index) {
         $endIndex = $tokens->getNextTokenOfKind($index, array(';', array(T_CLOSE_TAG)));
         $previous = $tokens->getPrevMeaningfulToken($endIndex);
         if ($tokens[$previous]->equals('}')) {
             $start = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $previous, false);
             $declarationContent = $tokens->generatePartialCode($start + 1, $previous - 1);
             $prefix = '';
             for ($i = $index + 1; $i < $start; ++$i) {
                 $prefix .= $tokens[$i]->getContent();
             }
             $prefix = ' ' . ltrim($prefix);
         } else {
             $declarationContent = $tokens->generatePartialCode($index + 1, $endIndex - 1);
             $prefix = ' ';
         }
         $declarationParts = explode(',', $declarationContent);
         if (1 === count($declarationParts)) {
             continue;
         }
         $declarationContent = array();
         foreach ($declarationParts as $declarationPart) {
             $declarationContent[] = 'use' . $prefix . trim($declarationPart) . ';';
         }
         $declarationContent = implode("\n" . $this->detectIndent($tokens, $index), $declarationContent);
         for ($i = $index; $i < $endIndex; ++$i) {
             $tokens[$i]->clear();
         }
         if ($tokens[$endIndex]->equals(';')) {
             $tokens[$endIndex]->clear();
         }
         $declarationTokens = Tokens::fromCode('<?php ' . $declarationContent);
         $declarationTokens[0]->clear();
         $declarationTokens->clearEmptyTokens();
         $tokens->insertAt($index, $declarationTokens);
     }
 }
 /**
  * {@inheritdoc}
  */
 public function supports(\SplFileInfo $file)
 {
     if ($file instanceof StdinFileInfo) {
         return false;
     }
     $filenameParts = explode('.', $file->getBasename(), 2);
     if (!isset($filenameParts[1]) || 'php' !== $filenameParts[1] || 0 === preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*$/', $filenameParts[0]) || '__halt_compiler' === $filenameParts[0]) {
         return false;
     }
     try {
         $tokens = Tokens::fromCode(sprintf('<?php class %s {}', $filenameParts[0]));
         if ($tokens[3]->isKeyword() || $tokens[3]->isMagicConstant()) {
             // name can not be a class name - detected by PHP 5.x
             return false;
         }
     } catch (\ParseError $e) {
         // name can not be a class name - detected by PHP 7.x
         return false;
     }
     // ignore stubs/fixtures, since they are typically containing invalid files for various reasons
     return !preg_match('{[/\\\\](stub|fixture)s?[/\\\\]}i', $file->getRealPath());
 }
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $namespacesImports = $tokensAnalyzer->getImportUseIndexes(true);
     if (0 === count($namespacesImports)) {
         return;
     }
     $usesOrder = array();
     foreach ($namespacesImports as $uses) {
         $usesOrder = array_replace($usesOrder, $this->getNewOrder(array_reverse($uses), $tokens));
     }
     $usesOrder = array_reverse($usesOrder, true);
     $mapStartToEnd = array();
     foreach ($usesOrder as $use) {
         $mapStartToEnd[$use['startIndex']] = $use['endIndex'];
     }
     // Now insert the new tokens, starting from the end
     foreach ($usesOrder as $index => $use) {
         $declarationTokens = Tokens::fromCode('<?php use ' . $use['namespace'] . ';');
         $declarationTokens->clearRange(0, 2);
         // clear `<?php use `
         $declarationTokens[count($declarationTokens) - 1]->clear();
         // clear `;`
         $declarationTokens->clearEmptyTokens();
         $tokens->overrideRange($index, $mapStartToEnd[$index], $declarationTokens);
         if ($use['group']) {
             // a group import must start with `use` and cannot be part of comma separated import list
             $prev = $tokens->getPrevMeaningfulToken($index);
             if ($tokens[$prev]->equals(',')) {
                 $tokens[$prev]->setContent(';');
                 $tokens->insertAt($prev + 1, new Token(array(T_USE, 'use')));
                 if (!$tokens[$prev + 2]->isWhitespace()) {
                     $tokens->insertAt($prev + 2, new Token(array(T_WHITESPACE, ' ')));
                 }
             }
         }
     }
 }
 /**
  * @dataProvider provideBlockDetectionCases
  */
 public function testBlockDetection(array $expected, $source, $index)
 {
     Tokens::clearCache();
     $tokens = Tokens::fromCode($source);
     $fixer = $this->getFixer();
     $method = new \ReflectionMethod($fixer, 'getPreviousBlock');
     $method->setAccessible(true);
     $result = $method->invoke($fixer, $tokens, $index);
     $this->assertSame($expected, $result);
 }
 /**
  * @dataProvider provideFindHeaderCommentInsertionIndexCases
  */
 public function testFindHeaderCommentInsertionIndex($expected, $code, array $config)
 {
     Tokens::clearCache();
     $tokens = Tokens::fromCode($code);
     $fixer = $this->getFixer();
     $fixer->configure($config);
     $method = new \ReflectionMethod($fixer, 'findHeaderCommentInsertionIndex');
     $method->setAccessible(true);
     $this->assertSame($expected, $method->invoke($fixer, $tokens));
 }
 /**
  * @dataProvider provideCases
  */
 public function testCountArguments($code, $openIndex, $closeIndex, $argumentsCount)
 {
     $mock = new AccessibleObject($this->getMockForAbstractClass('\\PhpCsFixer\\AbstractFunctionReferenceFixer'));
     $this->assertSame($argumentsCount, $mock->countArguments(Tokens::fromCode($code), $openIndex, $closeIndex));
 }
Esempio n. 15
0
 /**
  * @param string  $source
  * @param int[]   $indexes
  * @param Token[] $expected
  */
 private function doTestClearTokens($source, array $indexes, array $expected)
 {
     Tokens::clearCache();
     $tokens = Tokens::fromCode($source);
     foreach ($indexes as $index) {
         $tokens->clearTokenAndMergeSurroundingWhitespace($index);
     }
     $this->assertSame(count($expected), $tokens->count());
     foreach ($expected as $index => $expectedToken) {
         $token = $tokens[$index];
         $expectedPrototype = $expectedToken->getPrototype();
         if (is_array($expectedPrototype)) {
             unset($expectedPrototype[2]);
             // don't compare token lines as our token mutations don't deal with line numbers
         }
         $this->assertTrue($token->equals($expectedPrototype), sprintf('The token at index %d should be %s, got %s', $index, json_encode($expectedPrototype), $token->toJson()));
     }
 }
 /**
  * Tests if a fixer fixes a given string to match the expected result.
  *
  * It is used both if you want to test if something is fixed or if it is not touched by the fixer.
  * It also makes sure that the expected output does not change when run through the fixer. That means that you
  * do not need two test cases like [$expected] and [$expected, $input] (where $expected is the same in both cases)
  * as the latter covers both of them.
  * This method throws an exception if $expected and $input are equal to prevent test cases that accidentally do
  * not test anything.
  *
  * @param string              $expected The expected fixer output.
  * @param string|null         $input    The fixer input, or null if it should intentionally be equal to the output.
  * @param \SplFileInfo|null   $file     The file to fix, or null if unneeded.
  * @param FixerInterface|null $fixer    The fixer to be used, or null if it should be inferred from the test name.
  */
 protected function doTest($expected, $input = null, \SplFileInfo $file = null, FixerInterface $fixer = null)
 {
     if ($expected === $input) {
         throw new \InvalidArgumentException('Input parameter must not be equal to expected parameter.');
     }
     $fixer = $fixer ?: $this->getFixer();
     $file = $file ?: $this->getTestFile();
     $fileIsSupported = $fixer->supports($file);
     if (null !== $input) {
         $this->assertNull($this->lintSource($input));
         Tokens::clearCache();
         $tokens = Tokens::fromCode($input);
         if ($fileIsSupported) {
             $this->assertTrue($fixer->isCandidate($tokens), 'Fixer must be a candidate for input code.');
             $fixResult = $fixer->fix($file, $tokens);
             $this->assertNull($fixResult, '->fix method must return null.');
         }
         $this->assertTrue($tokens->isChanged(), 'Tokens collection built on input code must be marked as changed after fixing.');
         $this->assertSame($expected, $tokens->generateCode(), 'Code build on input code must match expected code.');
         Tokens::clearCache();
         $expectedTokens = Tokens::fromCode($expected);
         $tokens->clearEmptyTokens();
         $this->assertTokens($expectedTokens, $tokens);
     }
     $this->assertNull($this->lintSource($expected));
     Tokens::clearCache();
     $tokens = Tokens::fromCode($expected);
     if ($fileIsSupported) {
         $fixResult = $fixer->fix($file, $tokens);
         $this->assertNull($fixResult, '->fix method must return null.');
     }
     $this->assertFalse($tokens->isChanged(), 'Tokens collection built on expected code must not be marked as changed after fixing.');
     $this->assertSame($expected, $tokens->generateCode(), 'Code build on expected code must not change.');
 }
Esempio n. 17
0
 /**
  * {@inheritdoc}
  */
 public function fix(\SplFileInfo $file, Tokens $tokens)
 {
     $namespace = false;
     $namespaceIndex = 0;
     $namespaceEndIndex = 0;
     $classyName = null;
     $classyIndex = 0;
     foreach ($tokens as $index => $token) {
         if ($token->isGivenKind(T_NAMESPACE)) {
             if (false !== $namespace) {
                 return;
             }
             $namespaceIndex = $tokens->getNextMeaningfulToken($index);
             $namespaceEndIndex = $tokens->getNextTokenOfKind($index, array(';'));
             $namespace = trim($tokens->generatePartialCode($namespaceIndex, $namespaceEndIndex - 1));
         } elseif ($token->isClassy()) {
             if (null !== $classyName) {
                 return;
             }
             $classyIndex = $tokens->getNextMeaningfulToken($index);
             $classyName = $tokens[$classyIndex]->getContent();
         }
     }
     if (null === $classyName) {
         return;
     }
     if (false !== $namespace) {
         $normNamespace = str_replace('\\', '/', $namespace);
         $path = str_replace('\\', '/', $file->getRealPath());
         $dir = dirname($path);
         if (isset($this->configuration['dir'])) {
             $dir = substr($dir, strlen(realpath($this->configuration['dir'])) + 1);
             if (false === $dir) {
                 $dir = '';
             }
             if (strlen($normNamespace) > strlen($dir)) {
                 if ('' !== $dir) {
                     $normNamespace = substr($normNamespace, -strlen($dir));
                 } else {
                     $normNamespace = '';
                 }
             }
         }
         $dir = substr($dir, -strlen($normNamespace));
         if (false === $dir) {
             $dir = '';
         }
         $filename = basename($path, '.php');
         if ($classyName !== $filename) {
             $tokens[$classyIndex]->setContent($filename);
         }
         if ($normNamespace !== $dir && strtolower($normNamespace) === strtolower($dir)) {
             for ($i = $namespaceIndex; $i <= $namespaceEndIndex; ++$i) {
                 $tokens[$i]->clear();
             }
             $namespace = substr($namespace, 0, -strlen($dir)) . str_replace('/', '\\', $dir);
             $newNamespace = Tokens::fromCode('<?php namespace ' . $namespace . ';');
             $newNamespace[0]->clear();
             $newNamespace[1]->clear();
             $newNamespace[2]->clear();
             $newNamespace->clearEmptyTokens();
             $tokens->insertAt($namespaceIndex, $newNamespace);
         }
     } else {
         $normClass = str_replace('_', '/', $classyName);
         $path = str_replace('\\', '/', $file->getRealPath());
         $filename = substr($path, -strlen($normClass) - 4, -4);
         if ($normClass !== $filename && strtolower($normClass) === strtolower($filename)) {
             $tokens[$classyIndex]->setContent(str_replace('/', '_', $filename));
         }
     }
 }
 /**
  * @param OutputInterface $output
  * @param string          $name
  */
 private function describeRule(OutputInterface $output, $name)
 {
     $fixers = $this->getFixers();
     if (!isset($fixers[$name])) {
         throw new DescribeNameNotFoundException($name, 'rule');
     }
     /** @var FixerInterface $fixer */
     $fixer = $fixers[$name];
     if ($fixer instanceof DefinedFixerInterface) {
         $definition = $fixer->getDefinition();
     } else {
         $definition = new ShortFixerDefinition('Description is not availble.');
     }
     $output->writeln(sprintf('<info>Description of</info> %s <info>rule</info>.', $name));
     $output->writeln($definition->getSummary());
     if ($definition->getDescription()) {
         $output->writeln($definition->getDescription());
     }
     $output->writeln('');
     if ($fixer->isRisky()) {
         $output->writeln('<error>Fixer applying this rule is risky.</error>');
         if ($definition->getRiskyDescription()) {
             $output->writeln($definition->getRiskyDescription());
         }
         $output->writeln('');
     }
     if ($fixer instanceof ConfigurableFixerInterface) {
         $output->writeln('<comment>Fixer is configurable.</comment>');
         if ($definition->getConfigurationDescription()) {
             $output->writeln($definition->getConfigurationDescription());
         }
         if ($definition->getDefaultConfiguration()) {
             $output->writeln(sprintf('Default configuration: <comment>%s</comment>.', $this->arrayToText($definition->getDefaultConfiguration())));
         }
         $output->writeln('');
     }
     if ($definition->getCodeSamples()) {
         $output->writeln('Fixing examples:');
         $differ = new SebastianBergmannDiffer();
         $diffFormatter = new DiffConsoleFormatter($output->isDecorated(), sprintf('<comment>   ---------- begin diff ----------</comment>%s%%s%s<comment>   ----------- end diff -----------</comment>', PHP_EOL, PHP_EOL));
         foreach ($definition->getCodeSamples() as $index => $codeSample) {
             $old = $codeSample->getCode();
             $tokens = Tokens::fromCode($old);
             if ($fixer instanceof ConfigurableFixerInterface) {
                 $fixer->configure($codeSample->getConfiguration());
             }
             $fixer->fix(new StdinFileInfo(), $tokens);
             $new = $tokens->generateCode();
             $diff = $differ->diff($old, $new);
             if (null === $codeSample->getConfiguration()) {
                 $output->writeln(sprintf(' * Example #%d.', $index + 1));
             } else {
                 $output->writeln(sprintf(' * Example #%d. Fixing with configuration: <comment>%s</comment>.', $index + 1, $this->arrayToText($codeSample->getConfiguration())));
             }
             $output->writeln($diffFormatter->format($diff, '   %s'));
             $output->writeln('');
         }
     }
     if ($definition instanceof ShortFixerDefinition) {
         $output->writeln(sprintf('<question>This rule is not yet described, do you want to help us and describe it?</question>'));
         $output->writeln('Contribute at <comment>https://github.com/FriendsOfPHP/PHP-CS-Fixer</comment> !');
         $output->writeln('');
     }
 }
Esempio n. 19
0
 public function fixFile(\SplFileInfo $file, array $fixers, $dryRun, $diff, FileCacheManager $fileCacheManager)
 {
     $new = $old = file_get_contents($file->getRealPath());
     $name = $this->getFileRelativePathname($file);
     if ('' === $old || !$fileCacheManager->needFixing($name, $old) || PHP_VERSION_ID >= 50306 && PHP_VERSION_ID < 50400 && false !== stripos($old, '__halt_compiler()')) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_SKIPPED));
         return;
     }
     try {
         $this->linter->lintFile($file->getRealPath());
     } catch (LintingException $e) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_INVALID));
         $this->errorsManager->report(new Error(Error::TYPE_INVALID, $name));
         return;
     }
     $appliedFixers = array();
     // we do not need Tokens to still caching previously fixed file - so clear the cache
     Tokens::clearCache();
     $tokens = Tokens::fromCode($old);
     $newHash = $oldHash = $tokens->getCodeHash();
     try {
         foreach ($fixers as $fixer) {
             if (!$fixer->supports($file) || !$fixer->isCandidate($tokens)) {
                 continue;
             }
             $fixer->fix($file, $tokens);
             if ($tokens->isChanged()) {
                 $tokens->clearEmptyTokens();
                 $tokens->clearChanged();
                 $appliedFixers[] = $fixer->getName();
             }
         }
     } catch (\Exception $e) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_EXCEPTION));
         $this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $name));
         return;
     }
     $fixInfo = null;
     if (!empty($appliedFixers)) {
         $new = $tokens->generateCode();
         $newHash = $tokens->getCodeHash();
     }
     // We need to check if content was changed and then applied changes.
     // But we can't simple check $appliedFixers, because one fixer may revert
     // work of other and both of them will mark collection as changed.
     // Therefore we need to check if code hashes changed.
     if ($oldHash !== $newHash) {
         try {
             $this->linter->lintSource($new);
         } catch (LintingException $e) {
             $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_LINT));
             $this->errorsManager->report(new Error(Error::TYPE_LINT, $name));
             return;
         }
         if (!$dryRun && false === @file_put_contents($file->getRealPath(), $new)) {
             $error = error_get_last();
             if ($error) {
                 throw new IOException(sprintf('Failed to write file "%s", "%s".', $file->getRealpath(), $error['message']), 0, null, $file->getRealpath());
             }
             throw new IOException(sprintf('Failed to write file "%s".', $file->getRealpath()), 0, null, $file->getRealpath());
         }
         $fixInfo = array('appliedFixers' => $appliedFixers);
         if ($diff) {
             $fixInfo['diff'] = $this->stringDiff($old, $new);
         }
     }
     $fileCacheManager->setFile($name, $new);
     $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES));
     return $fixInfo;
 }
 private function fixGroupUse(Tokens $tokens, $index, $endIndex)
 {
     list($groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment) = $this->getGroupDeclaration($tokens, $index);
     $statements = $this->getGroupStatements($tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment);
     if (count($statements) < 2) {
         return;
     }
     $tokens->clearRange($index, $groupCloseIndex);
     if ($tokens[$endIndex]->equals(';')) {
         $tokens[$endIndex]->clear();
     }
     $ending = $this->whitespacesConfig->getLineEnding();
     $importTokens = Tokens::fromCode('<?php ' . implode($ending, $statements));
     $importTokens[0]->clear();
     $importTokens->clearEmptyTokens();
     $tokens->insertAt($index, $importTokens);
 }
Esempio n. 21
0
 /**
  * @dataProvider provideGetFunctionProperties
  */
 public function testGetFunctionProperties($source, $index, $expected)
 {
     $tokens = Tokens::fromCode($source);
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $attributes = $tokensAnalyzer->getMethodAttributes($index);
     $this->assertSame($expected, $attributes);
 }
 /**
  * @dataProvider getImportUseIndexesCasesPHP70
  * @requires PHP 7.0
  */
 public function testGetImportUseIndexesPHP70(array $expected, $input, $perNamespace = false)
 {
     $tokens = Tokens::fromCode($input);
     $tokensAnalyzer = new TokensAnalyzer($tokens);
     $this->assertSame($expected, $tokensAnalyzer->getImportUseIndexes($perNamespace));
 }
Esempio n. 23
0
    public function testFindGivenKind()
    {
        $source = <<<'PHP'
<?php
class FooBar
{
    public function foo()
    {
        return 'bar';
    }

    public function bar()
    {
        return 'foo';
    }
}
PHP;
        $tokens = Tokens::fromCode($source);
        /** @var Token[] $found */
        $found = $tokens->findGivenKind(T_CLASS);
        $this->assertTrue(is_array($found));
        $this->assertCount(1, $found);
        $this->assertArrayHasKey(1, $found);
        $this->assertSame(T_CLASS, $found[1]->getId());
        /** @var array $found */
        $found = $tokens->findGivenKind(array(T_CLASS, T_FUNCTION));
        $this->assertCount(2, $found);
        $this->assertArrayHasKey(T_CLASS, $found);
        $this->assertTrue(is_array($found[T_CLASS]));
        $this->assertCount(1, $found[T_CLASS]);
        $this->assertArrayHasKey(1, $found[T_CLASS]);
        $this->assertSame(T_CLASS, $found[T_CLASS][1]->getId());
        $this->assertArrayHasKey(T_FUNCTION, $found);
        $this->assertTrue(is_array($found[T_FUNCTION]));
        $this->assertCount(2, $found[T_FUNCTION]);
        $this->assertArrayHasKey(9, $found[T_FUNCTION]);
        $this->assertSame(T_FUNCTION, $found[T_FUNCTION][9]->getId());
        $this->assertArrayHasKey(26, $found[T_FUNCTION]);
        $this->assertSame(T_FUNCTION, $found[T_FUNCTION][26]->getId());
        // test offset and limits of the search
        $found = $tokens->findGivenKind(array(T_CLASS, T_FUNCTION), 10);
        $this->assertCount(0, $found[T_CLASS]);
        $this->assertCount(1, $found[T_FUNCTION]);
        $this->assertArrayHasKey(26, $found[T_FUNCTION]);
        $found = $tokens->findGivenKind(array(T_CLASS, T_FUNCTION), 2, 10);
        $this->assertCount(0, $found[T_CLASS]);
        $this->assertCount(1, $found[T_FUNCTION]);
        $this->assertArrayHasKey(9, $found[T_FUNCTION]);
    }
 /**
  * Tests if a fixer fixes a given string to match the expected result.
  *
  * It is used both if you want to test if something is fixed or if it is not touched by the fixer.
  * It also makes sure that the expected output does not change when run through the fixer. That means that you
  * do not need two test cases like [$expected] and [$expected, $input] (where $expected is the same in both cases)
  * as the latter covers both of them.
  * This method throws an exception if $expected and $input are equal to prevent test cases that accidentally do
  * not test anything.
  *
  * @param string              $expected The expected fixer output
  * @param string|null         $input    The fixer input, or null if it should intentionally be equal to the output
  * @param \SplFileInfo|null   $file     The file to fix, or null if unneeded
  * @param FixerInterface|null $fixer    The fixer to be used, or null if it should be inferred from the test name
  */
 protected function doTest($expected, $input = null, \SplFileInfo $file = null, FixerInterface $fixer = null)
 {
     if ($expected === $input) {
         throw new \InvalidArgumentException('Input parameter must not be equal to expected parameter.');
     }
     $fixer = $fixer ?: $this->getFixer();
     $file = $file ?: $this->getTestFile();
     $fileIsSupported = $fixer->supports($file);
     if (null !== $input) {
         $this->assertNull($this->lintSource($input));
         Tokens::clearCache();
         $tokens = Tokens::fromCode($input);
         if ($fileIsSupported) {
             $this->assertTrue($fixer->isCandidate($tokens), 'Fixer must be a candidate for input code.');
             $fixResult = $fixer->fix($file, $tokens);
             $this->assertNull($fixResult, '->fix method must return null.');
         }
         $this->assertSame($expected, $tokens->generateCode(), 'Code build on input code must match expected code.');
         $this->assertTrue($tokens->isChanged(), 'Tokens collection built on input code must be marked as changed after fixing.');
         $tokens->clearEmptyTokens();
         $this->assertSame(count($tokens), count(array_unique(array_map(function (Token $token) {
             return spl_object_hash($token);
         }, $tokens->toArray()))), 'Token items inside Tokens collection must be unique.');
         Tokens::clearCache();
         $expectedTokens = Tokens::fromCode($expected);
         $this->assertTokens($expectedTokens, $tokens);
     }
     $this->assertNull($this->lintSource($expected));
     Tokens::clearCache();
     $tokens = Tokens::fromCode($expected);
     $isCandidate = $fixer->isCandidate($tokens);
     $this->assertFalse($tokens->isChanged(), 'Fixer should not touch Tokens on candidate check.');
     if (!$isCandidate) {
         return;
     }
     if ($fileIsSupported) {
         $fixResult = $fixer->fix($file, $tokens);
         $this->assertNull($fixResult, '->fix method must return null.');
     }
     $this->assertSame($expected, $tokens->generateCode(), 'Code build on expected code must not change.');
     $this->assertFalse($tokens->isChanged(), 'Tokens collection built on expected code must not be marked as changed after fixing.');
 }
Esempio n. 25
0
 private function fixFile(\SplFileInfo $file, LintingResultInterface $lintingResult)
 {
     $name = $this->getFileRelativePathname($file);
     try {
         $lintingResult->check();
     } catch (LintingException $e) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_INVALID));
         $this->errorsManager->report(new Error(Error::TYPE_INVALID, $name));
         return;
     }
     $fixers = $this->config->getFixers();
     $old = file_get_contents($file->getRealPath());
     $tokens = Tokens::fromCode($old);
     $oldHash = $tokens->getCodeHash();
     $newHash = $oldHash;
     $new = $old;
     $appliedFixers = array();
     try {
         foreach ($fixers as $fixer) {
             if (!$fixer->supports($file) || !$fixer->isCandidate($tokens)) {
                 continue;
             }
             $fixer->fix($file, $tokens);
             if ($tokens->isChanged()) {
                 $tokens->clearEmptyTokens();
                 $tokens->clearChanged();
                 $appliedFixers[] = $fixer->getName();
             }
         }
     } catch (\Exception $e) {
         $this->processException($name);
         return;
     } catch (\ParseError $e) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_LINT));
         $this->errorsManager->report(new Error(Error::TYPE_LINT, $name));
         return;
     } catch (\Throwable $e) {
         $this->processException($name);
         return;
     }
     $fixInfo = null;
     if (!empty($appliedFixers)) {
         $new = $tokens->generateCode();
         $newHash = $tokens->getCodeHash();
     }
     // We need to check if content was changed and then applied changes.
     // But we can't simple check $appliedFixers, because one fixer may revert
     // work of other and both of them will mark collection as changed.
     // Therefore we need to check if code hashes changed.
     if ($oldHash !== $newHash) {
         try {
             $this->linter->lintSource($new)->check();
         } catch (LintingException $e) {
             $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_LINT));
             $this->errorsManager->report(new Error(Error::TYPE_LINT, $name));
             return;
         }
         if (!$this->isDryRun) {
             if (false === @file_put_contents($file->getRealPath(), $new)) {
                 $error = error_get_last();
                 if (null !== $error) {
                     throw new IOException(sprintf('Failed to write file "%s", "%s".', $file->getRealPath(), $error['message']), 0, null, $file->getRealPath());
                 }
                 throw new IOException(sprintf('Failed to write file "%s".', $file->getRealPath()), 0, null, $file->getRealPath());
             }
         }
         $fixInfo = array('appliedFixers' => $appliedFixers, 'diff' => $this->differ->diff($old, $new));
     }
     $this->cacheManager->setFile($name, $new);
     $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES));
     return $fixInfo;
 }
 /**
  * @param string $source     valid PHP source code
  * @param int    $startIndex start index of the comment block
  * @param int    $endIndex   expected index of the last token of the block
  * @param bool   $isEmpty    expected value of empty flag returned
  *
  * @dataProvider provideCommentBlockCases
  */
 public function testGetCommentBlock($source, $startIndex, $endIndex, $isEmpty)
 {
     Tokens::clearCache();
     $tokens = Tokens::fromCode($source);
     $this->assertTrue($tokens[$startIndex]->isComment(), sprintf('Misconfiguration of test, expected comment token at index "%d".', $startIndex));
     $fixer = $this->getFixer();
     $method = new \ReflectionMethod($fixer, 'getCommentBlock');
     $method->setAccessible(true);
     list($foundStart, $foundEnd, $foundIsEmpty) = $method->invoke($fixer, $tokens, $startIndex);
     $this->assertSame($startIndex, $foundStart, 'Find start index of block failed.');
     $this->assertSame($endIndex, $foundEnd, 'Find end index of block failed.');
     $this->assertSame($isEmpty, $foundIsEmpty, 'Is empty comment block detection failed.');
 }