Skip to content

Commit

Permalink
Merge pull request #22 from calevans/type_hints
Browse files Browse the repository at this point in the history
Type Hint Sniffs and helpers
  • Loading branch information
robertology authored Apr 10, 2018
2 parents 765636f + cc75213 commit f4db103
Show file tree
Hide file tree
Showing 32 changed files with 4,282 additions and 1 deletion.
69 changes: 69 additions & 0 deletions NocWorx/Helpers/Annotation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class Annotation
{

/** @var string */
private $name;

/** @var int */
private $startPointer;

/** @var int */
private $endPointer;

/** @var string|null */
private $parameters;

/** @var string|null */
private $content;

public function __construct(
string $name,
int $startPointer,
int $endPointer,
?string $parameters,
?string $content
)
{
$this->name = $name;
$this->startPointer = $startPointer;
$this->endPointer = $endPointer;
$this->parameters = $parameters;
$this->content = $content;
}

public function getName(): string
{
return $this->name;
}

public function getStartPointer(): int
{
return $this->startPointer;
}

public function getEndPointer(): int
{
return $this->endPointer;
}

public function getParameters(): ?string
{
return $this->parameters;
}

public function getContent(): ?string
{
return $this->content;
}

}
109 changes: 109 additions & 0 deletions NocWorx/Helpers/AnnotationHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class AnnotationHelper
{

/**
* @param \PHP_CodeSniffer\Files\File $codeSnifferFile
* @param int $pointer
* @param string $annotationName
* @return \NocWorx\Helpers\Annotation[]
*/
public static function getAnnotationsByName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $pointer, string $annotationName): array
{
$annotations = self::getAnnotations($codeSnifferFile, $pointer);
if (!array_key_exists($annotationName, $annotations)) {
return [];
}

return $annotations[$annotationName];
}

/**
* @param \PHP_CodeSniffer\Files\File $codeSnifferFile
* @param int $pointer
* @return \NocWorx\Helpers\Annotation[][]
*/
public static function getAnnotations(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $pointer): array
{
$annotations = [];

$docCommentOpenToken = DocCommentHelper::findDocCommentOpenToken($codeSnifferFile, $pointer);
if ($docCommentOpenToken === null) {
return $annotations;
}
$tokens = $codeSnifferFile->getTokens();
$i = $docCommentOpenToken + 1;
while ($i < $tokens[$docCommentOpenToken]['comment_closer']) {
if ($tokens[$i]['code'] !== T_DOC_COMMENT_TAG) {
$i++;
continue;
}

$annotationStartPointer = $i;
$annotationEndPointer = $i;

// Fix for wrong PHPCS parsing
$parenthesesLevel = substr_count($tokens[$i]['content'], '(') - substr_count($tokens[$i]['content'], ')');
$annotationCode = $tokens[$i]['content'];

for ($j = $i + 1; $j <= $tokens[$docCommentOpenToken]['comment_closer']; $j++) {
if ($tokens[$j]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
$i = $j;
break;
}

if ($tokens[$j]['code'] === T_DOC_COMMENT_TAG && $parenthesesLevel === 0) {
$i = $j;
break;
}

if ($tokens[$j]['code'] === T_DOC_COMMENT_STAR) {
continue;
}

if (in_array($tokens[$j]['code'], [T_DOC_COMMENT_TAG, T_DOC_COMMENT_STRING], true)) {
$annotationEndPointer = $j;
} elseif ($tokens[$j]['code'] === T_DOC_COMMENT_WHITESPACE) {
if (array_key_exists($j - 1, $tokens) && $tokens[$j - 1]['code'] === T_DOC_COMMENT_STAR) {
continue;
}
if (array_key_exists($j + 1, $tokens) && $tokens[$j + 1]['code'] === T_DOC_COMMENT_STAR) {
continue;
}
}

$parenthesesLevel += substr_count($tokens[$j]['content'], '(') - substr_count($tokens[$j]['content'], ')');
$annotationCode .= $tokens[$j]['content'];
}

$annotationName = $tokens[$annotationStartPointer]['content'];
$annotationParameters = null;
$annotationContent = null;
if (preg_match('~^(@[-a-zA-Z\\\\]+)(?:\((.*)\))?(?:\\s+(.+))?($)~s', trim($annotationCode), $matches)) {
$annotationName = $matches[1];
$annotationParameters = trim($matches[2]);
if ($annotationParameters === '') {
$annotationParameters = null;
}
$annotationContent = trim($matches[3]);
if ($annotationContent === '') {
$annotationContent = null;
}
}

$annotations[$annotationName][] = new Annotation($annotationName, $annotationStartPointer, $annotationEndPointer, $annotationParameters, $annotationContent);
}

return $annotations;
}

}
50 changes: 50 additions & 0 deletions NocWorx/Helpers/CatchHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class CatchHelper
{

/**
* @param \PHP_CodeSniffer\Files\File $phpcsFile
* @param \NocWorx\Helpers\UseStatement[] $useStatements
* @param mixed[] $catchToken
* @return string[]
*/
public static function findCatchedTypesInCatch(\PHP_CodeSniffer\Files\File $phpcsFile, array $useStatements, array $catchToken): array
{
$nameEndPointer = $catchToken['parenthesis_opener'];
$tokens = $phpcsFile->getTokens();
$catchedTypes = [];
do {
$nameStartPointer = TokenHelper::findNext($phpcsFile, array_merge([T_BITWISE_OR], TokenHelper::$nameTokenCodes), $nameEndPointer + 1, $catchToken['parenthesis_closer']);
if ($nameStartPointer === null) {
break;
}

if ($tokens[$nameStartPointer]['code'] === T_BITWISE_OR) {
/** @var int $nameStartPointer */
$nameStartPointer = TokenHelper::findNextEffective($phpcsFile, $nameStartPointer + 1, $catchToken['parenthesis_closer']);
}

$pointerAfterNameEndPointer = TokenHelper::findNextExcluding($phpcsFile, TokenHelper::$nameTokenCodes, $nameStartPointer + 1);
$nameEndPointer = $pointerAfterNameEndPointer === null ? $nameStartPointer : $pointerAfterNameEndPointer - 1;

$catchedTypes[] = NamespaceHelper::resolveClassName(
$phpcsFile,
TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer),
$useStatements,
$catchToken['parenthesis_opener']
);
} while (true);

return $catchedTypes;
}

}
56 changes: 56 additions & 0 deletions NocWorx/Helpers/ClassHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class ClassHelper
{

public static function getFullyQualifiedName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $classPointer): string
{
$name = sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, self::getName($codeSnifferFile, $classPointer));
$namespace = NamespaceHelper::findCurrentNamespaceName($codeSnifferFile, $classPointer);
return $namespace !== null ? sprintf('%s%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $namespace, $name) : $name;
}

public static function getName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $classPointer): string
{
$tokens = $codeSnifferFile->getTokens();
return $tokens[TokenHelper::findNext($codeSnifferFile, T_STRING, $classPointer + 1, $tokens[$classPointer]['scope_opener'])]['content'];
}

/**
* @param \PHP_CodeSniffer\Files\File $codeSnifferFile
* @return string[]
*/
public static function getAllNames(\PHP_CodeSniffer\Files\File $codeSnifferFile): array
{
$previousClassPointer = 0;

return array_map(
function (int $classPointer) use ($codeSnifferFile): string {
return self::getName($codeSnifferFile, $classPointer);
},
iterator_to_array(self::getAllClassPointers($codeSnifferFile, $previousClassPointer))
);
}

private static function getAllClassPointers(\PHP_CodeSniffer\Files\File $codeSnifferFile, int &$previousClassPointer): \Generator
{
do {
$nextClassPointer = TokenHelper::findNext($codeSnifferFile, TokenHelper::$typeKeywordTokenCodes, $previousClassPointer + 1);
if ($nextClassPointer === null) {
break;
}

$previousClassPointer = $nextClassPointer;
yield $nextClassPointer;
} while (true);
}

}
36 changes: 36 additions & 0 deletions NocWorx/Helpers/Comment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class Comment
{

/** @var int */
private $pointer;

/** @var string */
private $content;

public function __construct(int $pointer, string $content)
{
$this->pointer = $pointer;
$this->content = $content;
}

public function getPointer(): int
{
return $this->pointer;
}

public function getContent(): string
{
return $this->content;
}

}
70 changes: 70 additions & 0 deletions NocWorx/Helpers/ConstantHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php
declare(strict_types = 1);

/**
* @copyright Copyright (c) 2015 Slevomat.cz, s.r.o.
* @license https://github.com/slevomat/coding-standard/blob/master/LICENSE.md MIT Licence
*/

namespace NocWorx\Helpers;

class ConstantHelper
{

public static function getName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $constantPointer): string
{
$tokens = $codeSnifferFile->getTokens();
return $tokens[TokenHelper::findNext($codeSnifferFile, T_STRING, $constantPointer + 1)]['content'];
}

public static function getFullyQualifiedName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $constantPointer): string
{
$name = self::getName($codeSnifferFile, $constantPointer);
$namespace = NamespaceHelper::findCurrentNamespaceName($codeSnifferFile, $constantPointer);

return $namespace !== null ? sprintf('%s%s%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $namespace, NamespaceHelper::NAMESPACE_SEPARATOR, $name) : $name;
}

/**
* @param \PHP_CodeSniffer\Files\File $codeSnifferFile
* @return string[]
*/
public static function getAllNames(\PHP_CodeSniffer\Files\File $codeSnifferFile): array
{
$previousConstantPointer = 0;

return array_map(
function (int $constantPointer) use ($codeSnifferFile): string {
return self::getName($codeSnifferFile, $constantPointer);
},
array_filter(
iterator_to_array(self::getAllConstantPointers($codeSnifferFile, $previousConstantPointer)),
function (int $constantPointer) use ($codeSnifferFile): bool {
foreach (array_reverse($codeSnifferFile->getTokens()[$constantPointer]['conditions']) as $conditionTokenCode) {
if ($conditionTokenCode === T_NAMESPACE) {
return true;
}

return false;
}

return true;
}
)
);
}

private static function getAllConstantPointers(\PHP_CodeSniffer\Files\File $codeSnifferFile, int &$previousConstantPointer): \Generator
{
do {
$nextConstantPointer = TokenHelper::findNext($codeSnifferFile, T_CONST, $previousConstantPointer + 1);
if ($nextConstantPointer === null) {
break;
}

$previousConstantPointer = $nextConstantPointer;
yield $nextConstantPointer;
} while (true);
}

}
Loading

0 comments on commit f4db103

Please sign in to comment.