private function checkMethodBody(Tokens $tokens, $methodName, $methodStart, $methodEnd)
 {
     for ($index = $methodStart; $index < $methodEnd; ++$index) {
         if (!$tokens[$index]->isGivenKind(T_STRING) || !in_array($tokens[$index]->getContent(), ['func_get_args', 'func_get_arg', 'func_num_args'], true)) {
             continue;
         }
         $tokens->reportAt($index, new Message(E_ERROR, 'check_method_arguments_called_not_allowed', ['method' => $methodName, 'function' => $tokens[$index]->getContent()]));
         break;
     }
 }
 /**
  * @param array $expectedMessages The expected list of messages
  * @param string $input The input that is tokenized
  * @param \SplFileInfo|null $file
  * @param CheckerInterface|null $checker
  */
 protected function makeTest(array $expectedMessages, $input, \SplFileInfo $file = null, CheckerInterface $checker = null)
 {
     $checker = $checker ?: $this->getChecker();
     $file = $file ?: $this->getTestFile();
     $fileIsSupported = $checker->supports($file);
     Tokens::clearCache();
     $tokens = Tokens::fromCode($input);
     if ($fileIsSupported) {
         self::assertTrue($checker->isCandidate($tokens), 'Fixer must be a candidate for input code.');
         $checker->check($file, $tokens);
     }
     $iterator = new ReportedTokenIterator(new LineNumberIterator($tokens));
     $lineMessages = [];
     foreach ($iterator as $k => $messages) {
         $lineMessages[$k] = array_map(function (Message $message) {
             return $message->toArray();
         }, $messages);
     }
     self::assertEquals($expectedMessages, $lineMessages);
 }
 /**
  * @inheritdoc
  */
 public function check(\SplFileInfo $file, Tokens $tokens)
 {
     $tokenCount = $tokens->count();
     for ($index = 0; $index < $tokenCount; ++$index) {
         $token = $tokens[$index];
         if (!$token->isGivenKind(T_CLASS)) {
             continue;
         }
         $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
         $classStart = $tokens->getNextTokenOfKind($index, array('{'));
         $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
         // ignore class if it is abstract or already final
         if ($prevToken->isGivenKind(array(T_ABSTRACT, T_FINAL))) {
             $index = $classEnd;
             continue;
         }
         $classNameIndex = $tokens->getNextTokenOfKind($index, [[T_STRING]]);
         $className = $tokens[$classNameIndex]->getContent();
         $tokens->reportAt($index, new Message(E_ERROR, 'check_class_should_be_final', ['class' => $className]));
         $index = $classEnd;
     }
 }
Exemple #4
0
 /**
  * @param \SplFileInfo $file
  * @param \Symfony\CS\FixerInterface[] $fixers
  * @param CheckerInterface[] $checkers
  * @param bool $dryRun
  * @param bool $diff
  * @param FileCacheManager $fileCacheManager
  * @param FileMessageCacheManager $messageCacheManager
  *
  * @return array|null|void
  */
 public function fixFile(\SplFileInfo $file, array $fixers, $dryRun, $diff, FileCacheManager $fileCacheManager, array $checkers = array(), FileMessageCacheManager $messageCacheManager = null)
 {
     $new = $old = file_get_contents($file->getRealpath());
     if ('' === $old || !$fileCacheManager->needFixing($this->getFileRelativePathname($file), $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 false;
     }
     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, $this->getFileRelativePathname($file)));
         return false;
     }
     $old = file_get_contents($file->getRealpath());
     // 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();
     $checkMessages = [];
     try {
         if ($dryRun) {
             $checkMessages = $this->runCheckers($file, $checkers, $tokens);
         }
         $appliedFixers = $this->runFixers($file, $fixers, $tokens);
         if (!$dryRun) {
             $checkMessages = $this->runCheckers($file, $checkers, $tokens);
         }
     } catch (\Exception $e) {
         $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus(FixerFileProcessedEvent::STATUS_EXCEPTION));
         $this->errorsManager->report(new Error(Error::TYPE_EXCEPTION, $this->getFileRelativePathname($file)));
         return false;
     }
     $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, $this->getFileRelativePathname($file)));
             return false;
         }
         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, 'checkMessages' => $checkMessages);
         if ($diff) {
             $fixInfo['diff'] = $this->stringDiff($old, $new);
         }
     } elseif (!empty($checkMessages)) {
         $fixInfo = array('checkMessages' => $checkMessages);
     }
     $fileCacheManager->setFile($this->getFileRelativePathname($file), $new);
     if ($messageCacheManager !== null) {
         $messageCacheManager->setMessages($this->getFileRelativePathname($file), isset($fixInfo['checkMessages']) ? $fixInfo['checkMessages'] : []);
     }
     $this->dispatchEvent(FixerFileProcessedEvent::NAME, FixerFileProcessedEvent::create()->setStatus($fixInfo ? FixerFileProcessedEvent::STATUS_FIXED : FixerFileProcessedEvent::STATUS_NO_CHANGES));
     return $fixInfo;
 }
 private function checkMethod(Tokens $tokens, $index, $attributes)
 {
     if ($attributes['name'] !== '__construct') {
         $tokens->reportAt($index, new Message(E_ERROR, 'check_class_must_not_contain_method', ['method' => $attributes['name']]));
         return false;
     }
     if ($attributes['visibility'] === null) {
         $tokens->reportAt($index, new Message(E_ERROR, 'check_class_method_must_have_a_visibility', ['method' => $attributes['name']]));
     } elseif ($attributes['visibility'] !== T_PUBLIC) {
         $tokens->reportAt($index, new Message(E_ERROR, 'check_class_method_must_be_public', ['method' => $attributes['name'], 'visibility' => $attributes['visibility'] === T_PRIVATE ? 'private' : 'protected']));
     }
     $functionArguments = TokensHelper::getFunctionArguments($tokens, $index);
     // Ensure that all arguments are used
     $startBodyIndex = $tokens->getNextTokenOfKind($index, ['{']);
     $endBodyIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startBodyIndex, true);
     $usedVariables = [];
     for ($index = $endBodyIndex - 1; $index > $startBodyIndex; --$index) {
         $token = $tokens[$index];
         if (!$token->isGivenKind(T_VARIABLE) || $tokens[$index - 1]->isGivenKind(T_OBJECT_OPERATOR) || $tokens[$index + 1]->isGivenKind(T_OBJECT_OPERATOR)) {
             continue;
         }
         $usedVariables[$index] = $token->getContent();
     }
     // Report unused arguments
     $unusedArguments = array_diff(array_map(function ($info) {
         return $info['token']->getContent();
     }, $functionArguments), $usedVariables);
     foreach ($unusedArguments as $argumentIndex => $argument) {
         $tokens->reportAt($argumentIndex, new Message(E_ERROR, 'check_class_method_argument_not_used', ['method' => $attributes['name'], 'argument' => $argument]));
     }
     return ['arguments' => $functionArguments];
 }
 /**
  * @param \SplFileInfo $file
  * @param Tokens $tokens
  * @param $namespace
  * @param $namespaceIndex
  */
 public function checkNamespaceDirectory(\SplFileInfo $file, Tokens $tokens, $namespace, $namespaceIndex)
 {
     if ($namespace === null) {
         return;
     }
     $path = trim(preg_replace('#/+#', '/', $file->getPath()), '/');
     $parts = [];
     while (!isset($this->dirMap[$path])) {
         $pathPos = strrpos($path, '/');
         if ($pathPos === false) {
             return;
         }
         $parts[] = substr($path, $pathPos + 1);
         $path = substr($path, 0, $pathPos);
     }
     if (!isset($this->dirMap[$path])) {
         return;
     }
     $expectedNamespace = $this->dirMap[$path] . (empty($parts) ? '' : '\\' . implode('\\', array_reverse($parts)));
     if ($expectedNamespace !== $namespace) {
         $tokens->reportAt($namespaceIndex, new Message(E_ERROR, 'check_psr4_namespace_is_invalid', ['expected' => $expectedNamespace, 'namespace' => $namespace]));
     }
 }