Skip to content

Commit

Permalink
Merge branch '2.15' into 2.16
Browse files Browse the repository at this point in the history
  • Loading branch information
keradus committed Apr 10, 2020
2 parents e165e10 + 0945975 commit 63ad513
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 104 deletions.
178 changes: 140 additions & 38 deletions src/Fixer/Comment/HeaderCommentFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function isCandidate(Tokens $tokens)
/**
* {@inheritdoc}
*
* Must run after NoBlankLinesAfterPhpdocFixer.
* Must run after DeclareStrictTypesFixer, NoBlankLinesAfterPhpdocFixer.
*/
public function getPriority()
{
Expand All @@ -128,30 +128,46 @@ public function getPriority()
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens)
{
// figure out where the comment should be placed
$headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens);
$location = $this->configuration['location'];

// check if there is already a comment
$headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerNewIndex - 1);
$locationIndexes = [];
foreach (['after_open', 'after_declare_strict'] as $possibleLocation) {
$locationIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);

if (null === $headerCurrentIndex) {
if ('' === $this->configuration['header']) {
return; // header not found and none should be set, return
}
if (!isset($locationIndexes[$locationIndex]) || $possibleLocation === $location) {
$locationIndexes[$locationIndex] = $possibleLocation;

$this->insertHeader($tokens, $headerNewIndex);
} elseif ($this->getHeaderAsComment() !== $tokens[$headerCurrentIndex]->getContent()) {
$tokens->clearTokenAndMergeSurroundingWhitespace($headerCurrentIndex);
if ('' === $this->configuration['header']) {
return; // header found and cleared, none should be set, return
continue;
}

$this->insertHeader($tokens, $headerNewIndex);
} else {
$headerNewIndex = $headerCurrentIndex;
}

$this->fixWhiteSpaceAroundHeader($tokens, $headerNewIndex);
foreach (array_values($locationIndexes) as $possibleLocation) {
// figure out where the comment should be placed
$headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens, $possibleLocation);

// check if there is already a comment
$headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerNewIndex - 1);

if (null === $headerCurrentIndex) {
if ('' === $this->configuration['header'] || $possibleLocation !== $location) {
continue;
}

$this->insertHeader($tokens, $headerNewIndex);
} elseif ($this->getHeaderAsComment() !== $tokens[$headerCurrentIndex]->getContent() || $possibleLocation !== $location) {
$this->removeHeader($tokens, $headerCurrentIndex);

if ('' === $this->configuration['header']) {
continue;
}

if ($possibleLocation === $location) {
$this->insertHeader($tokens, $headerNewIndex);
}
} else {
$this->fixWhiteSpaceAroundHeader($tokens, $headerCurrentIndex);
}
}
}

/**
Expand Down Expand Up @@ -222,17 +238,41 @@ private function findHeaderCommentCurrentIndex(Tokens $tokens, $headerNewIndex)
{
$index = $tokens->getNextNonWhitespace($headerNewIndex);

return null === $index || !$tokens[$index]->isComment() ? null : $index;
if (null === $index || !$tokens[$index]->isComment()) {
return null;
}

$next = $index + 1;

if (!isset($tokens[$next]) || \in_array($this->configuration['separate'], ['top', 'none'], true) || !$tokens[$index]->isGivenKind(T_DOC_COMMENT)) {
return $index;
}

if ($tokens[$next]->isWhitespace()) {
if (!Preg::match('/^\h*\R\h*$/D', $tokens[$next]->getContent())) {
return $index;
}

++$next;
}

if (!isset($tokens[$next]) || !$tokens[$next]->isClassy() && !$tokens[$next]->isGivenKind(T_FUNCTION)) {
return $index;
}

return $this->getHeaderAsComment() === $tokens[$index]->getContent() ? $index : null;
}

/**
* Find the index where the header comment must be inserted.
*
* @param string $location
*
* @return int
*/
private function findHeaderCommentInsertionIndex(Tokens $tokens)
private function findHeaderCommentInsertionIndex(Tokens $tokens, $location)
{
if ('after_open' === $this->configuration['location']) {
if ('after_open' === $location) {
return 1;
}

Expand Down Expand Up @@ -287,24 +327,31 @@ private function fixWhiteSpaceAroundHeader(Tokens $tokens, $headerIndex)
$lineEnding = $this->whitespacesConfig->getLineEnding();

// fix lines after header comment
$expectedLineCount = 'both' === $this->configuration['separate'] || 'bottom' === $this->configuration['separate'] ? 2 : 1;
if (
('both' === $this->configuration['separate'] || 'bottom' === $this->configuration['separate'])
&& null !== $tokens->getNextMeaningfulToken($headerIndex)
) {
$expectedLineCount = 2;
} else {
$expectedLineCount = 1;
}
if ($headerIndex === \count($tokens) - 1) {
$tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount)]));
} else {
$afterCommentIndex = $tokens->getNextNonWhitespace($headerIndex);
$lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex + 1, null === $afterCommentIndex ? \count($tokens) : $afterCommentIndex);
$lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, 1);
if ($lineBreakCount < $expectedLineCount) {
$missing = str_repeat($lineEnding, $expectedLineCount - $lineBreakCount);
if ($tokens[$headerIndex + 1]->isWhitespace()) {
$tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $missing.$tokens[$headerIndex + 1]->getContent()]);
} else {
$tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, $missing]));
}
} elseif ($lineBreakCount > 2) {
// remove extra line endings
if ($tokens[$headerIndex + 1]->isWhitespace()) {
$tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $lineEnding.$lineEnding]);
}
} elseif ($lineBreakCount > $expectedLineCount && $tokens[$headerIndex + 1]->isWhitespace()) {
$newLinesToRemove = $lineBreakCount - $expectedLineCount;
$tokens[$headerIndex + 1] = new Token([
T_WHITESPACE,
Preg::replace("/^\\R{{$newLinesToRemove}}/", '', $tokens[$headerIndex + 1]->getContent()),
]);
}
}

Expand All @@ -317,27 +364,80 @@ private function fixWhiteSpaceAroundHeader(Tokens $tokens, $headerIndex)
$tokens[$prev] = new Token([T_OPEN_TAG, Preg::replace($regex, $lineEnding, $tokens[$prev]->getContent())]);
}

$lineBreakCount = $this->getLineBreakCount($tokens, $prev, $headerIndex);
$lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex, -1);
if ($lineBreakCount < $expectedLineCount) {
// because of the way the insert index was determined for header comment there cannot be an empty token here
$tokens->insertAt($headerIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount - $lineBreakCount)]));
}
}

/**
* @param int $indexStart
* @param int $indexEnd
* @param int $index
* @param int $direction
*
* @return int
*/
private function getLineBreakCount(Tokens $tokens, $indexStart, $indexEnd)
private function getLineBreakCount(Tokens $tokens, $index, $direction)
{
$lineCount = 0;
for ($i = $indexStart; $i < $indexEnd; ++$i) {
$lineCount += substr_count($tokens[$i]->getContent(), "\n");
$whitespace = '';

for ($index += $direction; isset($tokens[$index]); $index += $direction) {
$token = $tokens[$index];

if ($token->isWhitespace()) {
$whitespace .= $token->getContent();

continue;
}

if (-1 === $direction && $token->isGivenKind(T_OPEN_TAG)) {
$whitespace .= $token->getContent();
}

if ('' !== $token->getContent()) {
break;
}
}

return $lineCount;
return substr_count($whitespace, "\n");
}

private function removeHeader(Tokens $tokens, $index)
{
$prevIndex = $index - 1;
$prevToken = $tokens[$prevIndex];
$newlineRemoved = false;

if ($prevToken->isWhitespace()) {
$content = $prevToken->getContent();

if (Preg::match('/\R/', $content)) {
$newlineRemoved = true;
}

$content = Preg::replace('/\R?\h*$/', '', $content);

if ('' !== $content) {
$tokens[$prevIndex] = new Token([T_WHITESPACE, $content]);
} else {
$tokens->clearAt($prevIndex);
}
}

$nextIndex = $index + 1;
$nextToken = isset($tokens[$nextIndex]) ? $tokens[$nextIndex] : null;

if (!$newlineRemoved && null !== $nextToken && $nextToken->isWhitespace()) {
$content = Preg::replace('/^\R/', '', $nextToken->getContent());

if ('' !== $content) {
$tokens[$nextIndex] = new Token([T_WHITESPACE, $content]);
} else {
$tokens->clearAt($nextIndex);
}
}

$tokens->clearTokenAndMergeSurroundingWhitespace($index);
}

/**
Expand All @@ -346,5 +446,7 @@ private function getLineBreakCount(Tokens $tokens, $indexStart, $indexEnd)
private function insertHeader(Tokens $tokens, $index)
{
$tokens->insertAt($index, new Token([self::HEADER_COMMENT === $this->configuration['comment_type'] ? T_COMMENT : T_DOC_COMMENT, $this->getHeaderAsComment()]));

$this->fixWhiteSpaceAroundHeader($tokens, $index);
}
}
2 changes: 1 addition & 1 deletion src/Fixer/Strict/DeclareStrictTypesFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function getDefinition()
/**
* {@inheritdoc}
*
* Must run before BlankLineAfterOpeningTagFixer, DeclareEqualNormalizeFixer.
* Must run before BlankLineAfterOpeningTagFixer, DeclareEqualNormalizeFixer, HeaderCommentFixer.
*/
public function getPriority()
{
Expand Down
4 changes: 3 additions & 1 deletion src/ToolInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public function getComposerInstallationDetails()
if (null === $this->composerInstallationDetails) {
$composerInstalled = json_decode(file_get_contents($this->getComposerInstalledFile()), true);

foreach ($composerInstalled as $package) {
$packages = isset($composerInstalled['packages']) ? $composerInstalled['packages'] : $composerInstalled;

foreach ($packages as $package) {
if (\in_array($package['name'], [self::COMPOSER_PACKAGE_NAME, self::COMPOSER_LEGACY_PACKAGE_NAME], true)) {
$this->composerInstallationDetails = $package;

Expand Down
1 change: 1 addition & 0 deletions tests/AutoReview/FixerFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public function provideFixersPriorityCases()
[$fixers['combine_nested_dirname'], $fixers['no_spaces_inside_parenthesis']],
[$fixers['declare_strict_types'], $fixers['blank_line_after_opening_tag']],
[$fixers['declare_strict_types'], $fixers['declare_equal_normalize']],
[$fixers['declare_strict_types'], $fixers['header_comment']],
[$fixers['dir_constant'], $fixers['combine_nested_dirname']],
[$fixers['doctrine_annotation_array_assignment'], $fixers['doctrine_annotation_spaces']],
[$fixers['elseif'], $fixers['braces']],
Expand Down
Loading

0 comments on commit 63ad513

Please sign in to comment.