1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
<?php declare(strict_types = 1);
namespace PHPStan\PhpDocParser\Printer;
use LogicException;
use PhpParser\Comment\Doc;
use PhpParser\Internal\TokenStream;
use PhpParser\Node as PhpNode;
use PhpParser\NodeTraverser as PhpParserNodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor as PhpParserCloningVisitor;
use PhpParser\NodeVisitorAbstract;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
use PHPStan\PhpDocParser\Ast\AbstractNodeVisitor;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\NodeTraverser;
use PHPStan\PhpDocParser\Ast\NodeVisitor;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\PhpDocParser\ParserConfig;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use function file_get_contents;
use function str_repeat;
class IntegrationPrinterWithPhpParserTest extends TestCase
{
private const TAB_WIDTH = 4;
/**
* @return iterable<array{string, string, NodeVisitor}>
*/
public static function dataPrint(): iterable
{
$insertParameter = new class () extends AbstractNodeVisitor {
public function enterNode(Node $node)
{
if ($node instanceof PhpDocNode) {
$node->children[] = new PhpDocTagNode('@param', new ParamTagValueNode(
new IdentifierTypeNode('Bar'),
false,
'$b',
'',
false,
));
}
return $node;
}
};
yield [
__DIR__ . '/data/printer-1-spaces-before.php',
__DIR__ . '/data/printer-1-spaces-after.php',
$insertParameter,
];
}
/**
* @dataProvider dataPrint
*/
#[DataProvider('dataPrint')]
public function testPrint(string $file, string $expectedFile, NodeVisitor $visitor): void
{
$phpParserFactory = new ParserFactory();
$phpParser = $phpParserFactory->createForNewestSupportedVersion();
$phpTraverser = new PhpParserNodeTraverser();
$phpTraverser->addVisitor(new PhpParserCloningVisitor());
$fileContents = file_get_contents($file);
if ($fileContents === false) {
$this->fail('Could not read ' . $file);
}
$oldStmts = $phpParser->parse($fileContents);
if ($oldStmts === null) {
throw new LogicException();
}
$oldTokens = $phpParser->getTokens();
$phpTraverserIndent = new PhpParserNodeTraverser();
$indentDetector = new PhpPrinterIndentationDetectorVisitor(new TokenStream($oldTokens, self::TAB_WIDTH));
$phpTraverserIndent->addVisitor($indentDetector);
$phpTraverserIndent->traverse($oldStmts);
$phpTraverser2 = new PhpParserNodeTraverser();
$phpTraverser2->addVisitor(new class ($visitor) extends NodeVisitorAbstract {
private NodeVisitor $visitor;
public function __construct(NodeVisitor $visitor)
{
$this->visitor = $visitor;
}
public function enterNode(PhpNode $phpNode)
{
if ($phpNode->getDocComment() === null) {
return null;
}
$phpDoc = $phpNode->getDocComment()->getText();
$config = new ParserConfig(['lines' => true, 'indexes' => true]);
$constExprParser = new ConstExprParser($config);
$phpDocParser = new PhpDocParser(
$config,
new TypeParser($config, $constExprParser),
$constExprParser,
);
$lexer = new Lexer($config);
$tokens = new TokenIterator($lexer->tokenize($phpDoc));
$phpDocNode = $phpDocParser->parse($tokens);
$cloningTraverser = new NodeTraverser([new NodeVisitor\CloningVisitor()]);
$newNodes = $cloningTraverser->traverse([$phpDocNode]);
$changingTraverser = new NodeTraverser([$this->visitor]);
/** @var PhpDocNode $newNode */
[$newNode] = $changingTraverser->traverse($newNodes);
$printer = new Printer();
$newPhpDoc = $printer->printFormatPreserving($newNode, $phpDocNode, $tokens);
$phpNode->setDocComment(new Doc($newPhpDoc));
return $phpNode;
}
});
/** @var PhpNode[] $newStmts */
$newStmts = $phpTraverser->traverse($oldStmts);
$newStmts = $phpTraverser2->traverse($newStmts);
$printer = new Standard(['indent' => str_repeat($indentDetector->indentCharacter, $indentDetector->indentSize)]);
$newCode = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
$this->assertStringEqualsFile($expectedFile, $newCode);
}
}
|