Merge pull request #1513 from rectorphp/static

Make Symfony 4.3 + phpdoc-parser 0.3.4 compatible
This commit is contained in:
Tomáš Votruba 2019-05-31 13:58:33 +03:00 committed by GitHub
commit a69d08bac5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 158 additions and 28 deletions

View File

@ -18,23 +18,23 @@
"nette/robot-loader": "^3.1",
"nette/utils": "^2.5|^3.0",
"nikic/php-parser": "^4.2.2",
"phpstan/phpdoc-parser": "0.3.3",
"phpstan/phpdoc-parser": "^0.3.4",
"phpstan/phpstan": "0.11.6",
"sebastian/diff": "^3.0",
"symfony/console": "^3.4|^4.2",
"symfony/dependency-injection": "^3.4|^4.2",
"symfony/finder": "^3.4|^4.2",
"symfony/process": "^3.4|^4.2",
"symplify/package-builder": "^6.0"
"symplify/package-builder": "^6.0.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.14",
"ocramius/package-versions": "^1.4",
"phpunit/phpunit": "^7.5|^8.0",
"symplify/changelog-linker": "^6.0",
"symplify/easy-coding-standard": "^6.0",
"symplify/monorepo-builder": "^6.0",
"symplify/phpstan-extensions": "^6.0",
"symplify/changelog-linker": "^6.0.1",
"symplify/easy-coding-standard": "^6.0.1",
"symplify/monorepo-builder": "^6.0.1",
"symplify/phpstan-extensions": "^6.0.1",
"thecodingmachine/phpstan-strict-rules": "^0.11",
"tracy/tracy": "^2.5"
},

View File

@ -3660,7 +3660,7 @@ Remove extra parameters
- class: `Rector\Php\Rector\FuncCall\PregReplaceEModifierRector`
The /e modifier is no longer supported, use preg_replace_callback instead
The /e modifier is no longer supported, use preg_replace_callback instead
```diff
class SomeClass

View File

@ -917,7 +917,7 @@ if (true) {
```php
?>
<strong>feel</strong><?php
<strong>feel</strong><?php
```
<br>

View File

@ -40,4 +40,9 @@ final class Attribute
* @var string
*/
public const ANNOTATION_CLASS = 'annotation_class';
/**
* @var string
*/
public const ORIGINAL_CONTENT = 'original_content';
}

View File

@ -2,10 +2,12 @@
namespace Rector\BetterPhpDocParser\PhpDocParser;
use Nette\Utils\Strings;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\ParserException;
@ -106,6 +108,51 @@ final class BetterPhpDocParser extends PhpDocParser
$attributeAwareNode = $this->attributeAwareNodeFactory->createFromNode($node);
$attributeAwareNode->setAttribute(Attribute::PHP_DOC_NODE_INFO, new StartEndInfo($tokenStart, $tokenEnd));
// add original text, for keeping trimmed spaces
if ($attributeAwareNode instanceof PhpDocTextNode) {
$originalContent = $this->getOriginalContentFromTokenIterator($tokenIterator);
$currentText = $attributeAwareNode->text;
// we try to match original content without trimmed spaces
$currentTextPattern = '#' . preg_quote($currentText, '#') . '#s';
$currentTextPattern = Strings::replace($currentTextPattern, '#\s#', '\s+');
$match = Strings::match($originalContent, $currentTextPattern);
if (isset($match[0])) {
$attributeAwareNode->setAttribute(Attribute::ORIGINAL_CONTENT, $match[0]);
}
}
return $attributeAwareNode;
}
/**
* @todo cache per tokens array hash
*/
private function getOriginalContentFromTokenIterator(TokenIterator $tokenIterator): string
{
$originalTokens = $this->privatesAccessor->getPrivateProperty($tokenIterator, 'tokens');
$originalContent = '';
foreach ($originalTokens as $originalToken) {
// skip opening
if (Strings::match($originalToken[0], '#/\*\*#')) {
continue;
}
// skip closing
if (Strings::match($originalToken[0], '#\*\/#')) {
continue;
}
if (Strings::match($originalToken[0], '#^\s+\*#')) {
$originalToken[0] = PHP_EOL;
}
$originalContent .= $originalToken[0];
}
return trim($originalContent);
}
}

View File

@ -147,7 +147,7 @@ final class PhpDocInfoPrinter
}
if ($attributeAwareNode instanceof PhpDocTagNode) {
return $output . PHP_EOL . ' * ' . (string) $attributeAwareNode;
return $output . PHP_EOL . ' * ' . $attributeAwareNode;
}
if (! $attributeAwareNode instanceof PhpDocTextNode && ! $attributeAwareNode instanceof GenericTagValueNode && $startEndInfo) {
@ -158,7 +158,16 @@ final class PhpDocInfoPrinter
);
}
return $output . (string) $attributeAwareNode;
// fix multiline BC break - https://github.com/phpstan/phpdoc-parser/pull/26/files
if ($attributeAwareNode->getAttribute(Attribute::ORIGINAL_CONTENT)) {
$this->restoreOriginalSpacingInText($attributeAwareNode);
}
$content = (string) $attributeAwareNode;
$content = explode(PHP_EOL, $content);
$content = implode(PHP_EOL . ' * ', $content);
return $output . $content;
}
private function printEnd(string $output): string
@ -277,4 +286,38 @@ final class PhpDocInfoPrinter
return Strings::contains($this->phpDocInfo->getOriginalContent(), $phpDocTagNode->name . ' ');
}
/**
* @param PhpDocTextNode|AttributeAwareNodeInterface $attributeAwareNode
*/
private function restoreOriginalSpacingInText(AttributeAwareNodeInterface $attributeAwareNode): void
{
/** @var string $originalContent */
$originalContent = $attributeAwareNode->getAttribute(Attribute::ORIGINAL_CONTENT);
$oldSpaces = Strings::matchAll($originalContent, '#\s+#ms');
$newParts = Strings::split($attributeAwareNode->text, '#\s+#');
// we can't do this!
if (count($oldSpaces) + 1 !== count($newParts)) {
return;
}
$newText = '';
foreach ($newParts as $key => $newPart) {
$newText .= $newPart;
if (isset($oldSpaces[$key])) {
if (Strings::match($oldSpaces[$key][0], '#\n {1,}$#s')) {
// remove last extra space
$oldSpaces[$key][0] = Strings::substring($oldSpaces[$key][0], 0, -1);
}
$newText .= $oldSpaces[$key][0];
}
}
if ($newText) {
$attributeAwareNode->text = $newText;
}
}
}

View File

@ -0,0 +1,4 @@
/**
* This is just text
* why is this missing asterisk?
*/

View File

@ -0,0 +1,7 @@
/**
* Match this code:
* if (null === static::$instance) {
* static::$instance = new static();
* }
* return static::$instance;
*/

View File

@ -33,6 +33,7 @@ final class PhpDocInfoPrinterTest extends AbstractKernelTestCase
/**
* @dataProvider provideDocFilesForPrint()
* @dataProvider provideMultiline()
*/
public function testPrintFormatPreserving(string $docFilePath): void
{
@ -67,6 +68,12 @@ final class PhpDocInfoPrinterTest extends AbstractKernelTestCase
yield [__DIR__ . '/PhpDocInfoPrinterSource/doc13.txt'];
}
public function provideMultiline(): Iterator
{
yield [__DIR__ . '/PhpDocInfoPrinterSource/multiline1.txt'];
yield [__DIR__ . '/PhpDocInfoPrinterSource/multiline2.txt'];
}
/**
* @dataProvider provideDocFilesToEmpty()
*/

View File

@ -2,7 +2,6 @@
namespace Rector\CodeQuality\Rector\Array_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
@ -15,6 +14,7 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\Rector\AbstractRector;

View File

@ -161,6 +161,11 @@ final class UseAddingCommander implements CommanderInterface
{
$filePath = $this->getRealPathFromNode($node);
// already analysed
if (isset($this->useImportsInFilePath[$filePath])) {
return;
}
$usedImports = $this->usedImportsResolver->resolveForNode($node);
foreach ($usedImports as $usedImport) {

View File

@ -8,7 +8,6 @@ use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Nop;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;

View File

@ -2,9 +2,9 @@
namespace Rector\Php\Rector\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Scalar\LNumber;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;

View File

@ -10,6 +10,8 @@ use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Static_;
use PhpParser\Node\Stmt\StaticVar;
use PhpParser\Node\Stmt\Unset_;
use PHPStan\Analyser\Scope;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -93,15 +95,7 @@ CODE_SAMPLE
return null;
}
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Assign || $this->isStaticVariable($parentNode)) {
return null;
}
/** @var Scope|null $nodeScope */
$nodeScope = $node->getAttribute(AttributeKey::SCOPE);
if ($nodeScope === null) {
// possible in foreach variable
if ($this->shouldSkipVariable($node)) {
return null;
}
@ -111,14 +105,12 @@ CODE_SAMPLE
}
// defined 100 %
/** @var Scope $nodeScope */
$nodeScope = $node->getAttribute(AttributeKey::SCOPE);
if ($nodeScope->hasVariableType($variableName)->yes()) {
return null;
}
if ($parentNode instanceof Unset_ || $parentNode instanceof Node\Expr\Cast\Unset_) {
return null;
}
// @todo improve
$this->undefinedVariables[] = $variableName;
});
@ -142,13 +134,32 @@ CODE_SAMPLE
private function isStaticVariable(Node $parentNode): bool
{
// definition of static variable
if ($parentNode instanceof Node\Stmt\StaticVar) {
if ($parentNode instanceof StaticVar) {
$parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentParentNode instanceof Node\Stmt\Static_) {
if ($parentParentNode instanceof Static_) {
return true;
}
}
return false;
}
private function shouldSkipVariable(Variable $variable): bool
{
$parentNode = $variable->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Node) {
if ($parentNode instanceof Assign || $this->isStaticVariable($parentNode)) {
return true;
}
}
if ($parentNode instanceof Unset_ || $parentNode instanceof Node\Expr\Cast\Unset_) {
return true;
}
/** @var Scope|null $nodeScope */
$nodeScope = $variable->getAttribute(AttributeKey::SCOPE);
return $nodeScope === null;
}
}

View File

@ -15,5 +15,7 @@ final class AutowiredEventDispatcher extends EventDispatcher
foreach ($eventSubscribers as $eventSubscriber) {
$this->addSubscriber($eventSubscriber);
}
parent::__construct();
}
}