Skip to content
Permalink
Browse files

Merge pull request #182 from kubawerlos/calculate-fixers-priorities

Calculate fixers priorities
  • Loading branch information
kubawerlos committed Nov 12, 2019
2 parents ced2b3d + 6d8eef1 commit d553cbaf5971adbd96a37077953f000121137bbc
@@ -84,6 +84,20 @@ public function fix(\SplFileInfo $file, Tokens $tokens): void
]
);
}

$priorityStartIndex = $tokens->getNextTokenOfKind($startIndex, [[T_RETURN]]) + 2;
if ($tokens[$priorityStartIndex]->isGivenKind(T_VARIABLE)) {
return;
}
$priorityEndIndex = $tokens->getNextTokenOfKind($priorityStartIndex, [';']) - 1;

$priorityCollection = PriorityCollection::create();
$priority = $priorityCollection->getPriorityFixer($className)->getPriority();

$priorityTokens = $priority < 0 ? [new Token('-')] : [];
$priorityTokens[] = new Token([T_LNUMBER, (string) \abs($priority)]);

$tokens->overrideRange($priorityStartIndex, $priorityEndIndex, $priorityTokens);
}

/**
@@ -94,21 +108,16 @@ private function getCommentsToInsert(string $className): array
$comments = [];
$priorityCollection = PriorityCollection::create();

if (!$priorityCollection->hasPriorityFixer($className)) {
return [];
}

$fixersToRunBefore = $priorityCollection->getPriorityFixer($className)->getFixersToRunBefore();
$fixersToRunBefore = $priorityCollection->getPriorityFixer($className)->getFixerToRunBeforeNames();
if ([] !== $fixersToRunBefore) {
$comments[] = new Token([
T_COMMENT,
\sprintf('// must be run after %s', \str_replace('`', '', Utils::naturalLanguageJoinWithBackticks($fixersToRunBefore))),
]);
}

$fixersToRunAfter = $priorityCollection->getPriorityFixer($className)->getFixersToRunAfter();
$fixersToRunAfter = $priorityCollection->getPriorityFixer($className)->getFixerToRunAfterNames();
if ([] !== $fixersToRunAfter) {
\sort($fixersToRunAfter);
$comments[] = new Token([
T_COMMENT,
\sprintf('// must be run before %s', \str_replace('`', '', Utils::naturalLanguageJoinWithBackticks($fixersToRunAfter))),
@@ -5,48 +5,84 @@
namespace PhpCsFixerCustomFixersDev\Priority;

use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\FixerFactory;
use PhpCsFixerCustomFixers\Fixers;
use Tests\PriorityTest;

final class PriorityCollection
{
/** @var PriorityFixer[] */
private $fixers = [];
private $priorityFixers = [];

public static function create(): self
{
static $instance;

if ($instance === null) {
$instance = new self();

$priorityTest = new PriorityTest();
foreach ($priorityTest->providePriorityCases() as [$firstFixer, $secondFixer]) {
$instance->priorityFixer($firstFixer)->addFixerToRunAfter($secondFixer);
$instance->priorityFixer($secondFixer)->addFixerToRunBefore($firstFixer);
}
}

return $instance;
}

public function hasPriorityFixer(string $name): bool
public function __construct()
{
return isset($this->fixers[$name]);
$fixerFactory = new FixerFactory();
$fixerFactory->registerBuiltInFixers();
foreach ($fixerFactory->getFixers() as $fixer) {
$this->priorityFixers[(new \ReflectionObject($fixer))->getShortName()] = new PriorityFixer($fixer, $fixer->getPriority());
}
foreach (new Fixers() as $fixer) {
$this->priorityFixers[(new \ReflectionObject($fixer))->getShortName()] = new PriorityFixer($fixer, null);
}

$priorityTest = new PriorityTest();
foreach ($priorityTest->providePriorityCases() as [$firstFixer, $secondFixer]) {
$this->priorityFixer($firstFixer)->addFixerToRunAfter($this->priorityFixer($secondFixer));
$this->priorityFixer($secondFixer)->addFixerToRunBefore($this->priorityFixer($firstFixer));
}

$anythingChanged = true;
while ($this->isFixerWithoutPriorityInCollection()) {
if ($anythingChanged) {
$anythingChanged = false;
} else {
/** @var PriorityFixer $priorityFixer */
$priorityFixer = $this->getFirstPriorityFixerWithoutPriority();
$anythingChanged = $priorityFixer->calculatePriority(false);
}

foreach ($this->priorityFixers as $priorityFixer) {
if (!$priorityFixer->hasPriority()) {
$anythingChanged |= $priorityFixer->calculatePriority(true);
}
}
}
}

public function getPriorityFixer(string $name): PriorityFixer
{
return $this->fixers[$name];
return $this->priorityFixers[$name];
}

private function priorityFixer(FixerInterface $fixer): PriorityFixer
{
$name = (new \ReflectionObject($fixer))->getShortName();
return $this->priorityFixers[(new \ReflectionObject($fixer))->getShortName()];
}

private function isFixerWithoutPriorityInCollection(): bool
{
return $this->getFirstPriorityFixerWithoutPriority() instanceof PriorityFixer;
}

if (!isset($this->fixers[$name])) {
$this->fixers[$name] = new PriorityFixer();
private function getFirstPriorityFixerWithoutPriority(): ?PriorityFixer
{
foreach ($this->priorityFixers as $priorityFixer) {
if (!$priorityFixer->hasPriority()) {
return $priorityFixer;
}
}

return $this->fixers[$name];
return null;
}
}
@@ -8,29 +8,95 @@

final class PriorityFixer
{
/** @var string[] */
/** @var FixerInterface */
private $fixer;

/** @var self[] */
private $fixersToRunAfter = [];

/** @var string[] */
/** @var self[] */
private $fixersToRunBefore = [];

public function addFixerToRunAfter(FixerInterface $fixer): void
/** @var null|int */
private $priority;

public function __construct(FixerInterface $fixer, ?int $priority)
{
$this->fixer = $fixer;
$this->priority = $priority;
}

public function addFixerToRunAfter(self $priorityFixer): void
{
$this->fixersToRunAfter[] = (new \ReflectionObject($fixer))->getShortName();
$this->fixersToRunAfter[] = $priorityFixer;
}

public function addFixerToRunBefore(FixerInterface $fixer): void
public function addFixerToRunBefore(self $priorityFixer): void
{
$this->fixersToRunBefore[] = (new \ReflectionObject($fixer))->getShortName();
$this->fixersToRunBefore[] = $priorityFixer;
}

public function getFixersToRunAfter(): array
public function hasPriority(): bool
{
return $this->fixersToRunAfter;
return $this->priority !== null;
}

public function getFixersToRunBefore(): array
public function getPriority(): int
{
return $this->fixersToRunBefore;
if ($this->priority === null) {
throw new \Exception(\sprintf('Fixer %s has not priority calculated', $this->fixer->getName()));
}

return $this->priority;
}

public function getFixerToRunAfterNames(): array
{
return $this->getFixerNames($this->fixersToRunAfter);
}

public function getFixerToRunBeforeNames(): array
{
return $this->getFixerNames($this->fixersToRunBefore);
}

private function getFixerNames(array $priorityFixers): array
{
$fixers = \array_map(
static function (self $priorityFixer): string {
return (new \ReflectionObject($priorityFixer->fixer))->getShortName();
},
$priorityFixers
);

\sort($fixers);

return $fixers;
}

public function calculatePriority(bool $requireAllRelationHavePriority): bool
{
$priority = 0;
foreach ($this->fixersToRunBefore as $priorityFixer) {
if (!$priorityFixer->hasPriority()) {
if ($requireAllRelationHavePriority) {
return false;
}
continue;
}
$priority = \min($priority, $priorityFixer->getPriority() - 1);
}
foreach ($this->fixersToRunAfter as $priorityFixer) {
if (!$priorityFixer->hasPriority()) {
if ($requireAllRelationHavePriority) {
return false;
}
continue;
}
$priority = \max($priority, $priorityFixer->getPriority() + 1);
}
$this->priority = $priority;

return true;
}
}
@@ -25,7 +25,7 @@ public function getDefinition(): FixerDefinitionInterface

public function getPriority(): int
{
return 26;
return 0;
}

public function isCandidate(Tokens $tokens): bool
@@ -35,7 +35,7 @@ public function getPriority(): int
{
// must be run after CommentToPhpdocFixer and PhpdocAddMissingParamAnnotationFixer
// must be run before PhpdocAlignFixer
return 5;
return 0;
}

public function isCandidate(Tokens $tokens): bool
@@ -31,7 +31,7 @@ public function getPriority(): int
{
// must be run after CommentToPhpdocFixer
// must be run before PhpdocAlignFixer
return -2;
return 0;
}

public function isCandidate(Tokens $tokens): bool

0 comments on commit d553cba

Please sign in to comment.
You can’t perform that action at this time.