Skip to content

Commit

Permalink
Fixes #4. Implemented ErickSkrauch/ordered_overrides fixer
Browse files Browse the repository at this point in the history
  • Loading branch information
erickskrauch committed Jan 18, 2024
1 parent 4f379ec commit bb0bac3
Show file tree
Hide file tree
Showing 12 changed files with 638 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Enh #4: Introduce `ErickSkrauch\ordered_overrides` fixer.

## [1.2.4] - 2024-01-15
### Fixed
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,26 @@ Ensures that multiline if statement body curly brace placed on the right line.
* `keep_on_own_line` - should this place closing bracket on its own line? If it's set to `false`, than
curly bracket will be placed right after the last condition statement. **Default**: `true`.

### `ErickSkrauch/ordered_overrides`

Overridden and implemented methods must be sorted in the same order as they are defined in parent classes.

```diff
--- Original
+++ New
@@ @@
<?php
class Foo implements Serializable {

- public function unserialize($data) {}
+ public function serialize() {}

- public function serialize() {}
+ public function unserialize($data) {}

}
```

### `ErickSkrauch/remove_class_name_method_usages` (Yii2)

Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84)
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"phpspec/prophecy": "^1.15",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan": "^1.11.x-dev",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-strict-rules": "^1.5",
"phpunit/phpunit": "^9.5",
Expand Down
17 changes: 10 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions src/Analyzer/ClassNameAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);

namespace ErickSkrauch\PhpCsFixer\Analyzer;

use LogicException;
use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
use PhpCsFixer\Tokenizer\Tokens;

// TODO: better naming
// TODO: cover with tests
final class ClassNameAnalyzer {

private NamespacesAnalyzer $namespacesAnalyzer;

private NamespaceUsesAnalyzer $namespacesUsesAnalyzer;

public function __construct() {
$this->namespacesAnalyzer = new NamespacesAnalyzer();
$this->namespacesUsesAnalyzer = new NamespaceUsesAnalyzer();
}

/**
* @see https://www.php.net/manual/en/language.namespaces.rules.php
*
* @phpstan-return class-string
*/
public function getFqn(Tokens $tokens, int $classNameIndex): string {
$firstPart = $tokens[$classNameIndex];
if (!$firstPart->isGivenKind([T_STRING, T_NS_SEPARATOR])) {
throw new LogicException(sprintf('No T_STRING or T_NS_SEPARATOR at given index %d, got "%s".', $classNameIndex, $firstPart->getName()));
}

$relativeClassName = $this->readClassName($tokens, $classNameIndex);
if (str_starts_with($relativeClassName, '\\')) {
return $relativeClassName; // @phpstan-ignore return.type
}

$namespace = $this->namespacesAnalyzer->getNamespaceAt($tokens, $classNameIndex);
$uses = $this->namespacesUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace);
$parts = explode('\\', $relativeClassName, 2);
/** @var \PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis $use */
foreach ($uses as $use) {
if ($use->getShortName() !== $parts[0]) {
continue;
}

// @phpstan-ignore return.type
return '\\' . $use->getFullName() . (isset($parts[1]) ? ('\\' . $parts[1]) : '');
}

// @phpstan-ignore return.type
return ($namespace->getFullName() !== '' ? '\\' : '') . $namespace->getFullName() . '\\' . $relativeClassName;
}

private function readClassName(Tokens $tokens, int $classNameStart): string {
$className = '';
$index = $classNameStart;
do {
$token = $tokens[$index];
if ($token->isWhitespace()) {
continue;
}

$className .= $token->getContent();
} while ($tokens[++$index]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_WHITESPACE]));

return $className;
}

}
Loading

0 comments on commit bb0bac3

Please sign in to comment.