37 Commits
0.1.0 ... 0.4.0

Author SHA1 Message Date
de3a1f841c Fix GitHub Actions deprecation 2022-12-06 22:31:30 +01:00
243db94429 Prepare Readme 2022-12-06 22:27:18 +01:00
251ebc529c Fix fn spacing rule, upgrade to the latest PHP-CS-Fixer and add a new rule 2022-12-06 22:21:28 +01:00
2db4af0180 Adjust rules after production projects checks 2022-10-12 21:58:27 +02:00
f2d1b6164e Set correct minimal version of PHP-CS-Fixer 2022-10-06 04:34:17 +02:00
793b156b17 Remove const param from class_attributes_separation rule to allow grouping of consts with the same context 2022-10-05 17:10:11 +02:00
c3a8b869d1 Fix README.md 2022-09-22 18:02:19 +02:00
137a89820c Merge branch 'php-cs-fixer-3' 2022-09-20 02:51:02 +02:00
d4092c6e92 Add composer normalizer 2022-09-20 02:50:21 +02:00
5865b15c88 Introduce Github Actions as a replacement of the Travis CI 2022-09-20 02:50:21 +02:00
18806e41e2 Migrate to PHP-CS-Fixer 3. Upgrade custom rules. Upgrade ruleset. 2022-09-20 02:50:21 +02:00
ad25ce897b Allow PHP 8.0. There is no release since I need to go over the new rules, drop the old PHP versions and reimplement the CI 2021-05-13 16:18:57 +02:00
f327f14347 Bump minimal php-cs-fixer version to 2.15.0. Add additional rules. 2019-10-12 01:17:25 +03:00
bb403214d9 disable self_accessor rule 2019-04-30 17:30:49 +03:00
2140798d0a Update CHANGELOG 2019-02-23 20:29:08 +03:00
d8eafd4505 First set of fixes 2019-02-23 02:26:51 +03:00
714a38d53e Bump minimal php-cs-fixer version to 2.13.0. Add additional rules. 2019-02-23 02:05:20 +03:00
08483a26e2 Update CHANGELOG 2019-02-22 20:50:04 +03:00
3d5d40b2b7 Do not run CI on nightly php release [skip ci] 2019-02-22 20:46:40 +03:00
e617efc11c More accurate dependencies update 2019-02-22 20:43:39 +03:00
a6d1aa7265 Upgrade php-cs-fixer 2019-02-22 20:20:30 +03:00
3ab60f5bd5 Fix compatibility with the PHP-CS-Fixer 2.13.3 and above 2019-02-18 15:52:12 +03:00
06a37576ee Merge pull request #7 from cotsog/patch-1
Move test stage at the root
2018-08-15 17:24:30 +03:00
95e0f0f702 Move test stage at the root 2018-08-13 13:22:00 -04:00
0d20175b0a Add some cool shields 😙 2018-08-08 10:41:10 +03:00
4b480df97d Changelog.md added 2018-08-08 10:18:24 +03:00
50c7deed65 Downgrade test case 2018-08-07 12:25:47 +03:00
31661cd142 Pin dependencies to PHP 7.0 2018-08-07 12:12:55 +03:00
8ee5979288 Added array_syntax fixer 2018-08-07 12:07:27 +03:00
2480f7ba46 Adjust priority for LineBreakAfterStatementsFixer 2018-08-07 11:40:48 +03:00
824cf6c1f1 Fix LineBreakAfterStatementsFixer. Resolves #5. 2018-08-07 11:17:18 +03:00
fa40a02dfd Downgrade PHPUnit to 6.5 to pass testing on PHP 7.0 2018-08-06 12:45:25 +03:00
a7bef227df Add travis ci 2018-08-06 12:27:18 +03:00
59e9994662 Resolves #4. Add fixer to replace ::className() method usages with ::class keyword. 2018-08-06 11:59:44 +03:00
76bd14c167 Update dependencies 2018-08-06 10:07:29 +03:00
076c2f1c6c Fix readme 2018-04-18 15:43:54 +03:00
04e3690d06 Fix default value docs 2018-04-17 21:37:44 +03:00
23 changed files with 4099 additions and 1548 deletions

58
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: CI
on:
push:
pull_request:
jobs:
Build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-versions:
- '7.4'
- '8.0'
- '8.1'
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: ctype, mbstring
tools: cs2pr
- name: Get Composer's cache directory
id: composer-cache-path
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache Composer dependencies
uses: actions/cache@v3
id: composer-cache
with:
path: ${{ steps.composer-cache-path.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer install
- name: Normalize composer.json
if: matrix.php-versions == '8.1'
run: composer normalize --dry-run
- name: PHP-CS-Fixer
if: matrix.php-versions == '8.1'
run: vendor/bin/php-cs-fixer fix --dry-run --format=checkstyle | cs2pr
# https://github.com/marketplace/actions/setup-php-action#phpunit
- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: PHPUnit
run: vendor/bin/phpunit

8
.gitignore vendored
View File

@ -1,3 +1,5 @@
/vendor/
.php_cs
.php_cs.cache
vendor
dist
.phpunit.result.cache
.php-cs-fixer
.php-cs-fixer.cache

12
.php-cs-fixer.dist.php Normal file
View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
$finder = PhpCsFixer\Finder::create()
->in(__DIR__);
return Ely\CS\Config::create([
// Disable "parameters" and "match" to keep compatibility with PHP 7.4
'trailing_comma_in_multiline' => [
'elements' => ['arrays', 'arguments'],
],
])->setFinder($finder);

View File

@ -1,9 +0,0 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__);
return \Ely\CS\Config::create([
// Disable it for const, 'cause ^7.0 compatibility
'visibility_required' => ['property', 'method'],
])->setFinder($finder);

142
CHANGELOG.md Normal file
View File

@ -0,0 +1,142 @@
# Changelog
All notable changes to this project will be documented in this file.
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]
## [0.4.0] - 2022-12-06
### Added
- `simple_to_complex_string_variable` fixer.
- `single_trait_insert_per_statement` fixer.
- `native_function_type_declaration_casing` fixer.
- `php_unit_mock_short_will_return` fixer.
- `php_unit_dedicate_assert_internal_type` fixer.
- `php_unit_no_expectation_annotation` fixer.
- `modernize_strpos` fixer.
- `no_multiple_statements_per_line` fixer.
- `octal_notation` fixer.
- `class_reference_name_casing` fixer.
- `integer_literal_case` fixer.
- `no_unset_cast` fixer.
- `no_null_property_initialization` fixer.
- `comment_to_phpdoc` fixer.
- `multiline_comment_opening_closing` fixer.
- `no_empty_comment` fixer.
- `single_line_comment_spacing` fixer.
- `single_line_comment_style` fixer.
- `empty_loop_body` fixer.
- `empty_loop_condition` fixer.
- `switch_continue_to_break` fixer.
- `yoda_style` fixer in non-yoda mode.
- `function_typehint_space` fixer.
- `lambda_not_used_import` fixer.
- `no_unneeded_import_alias` fixer.
- `combine_consecutive_unsets` fixer.
- `declare_parentheses` fixer.
- `clean_namespace` fixer.
- `assign_null_coalescing_to_coalesce_equal` fixer.
- `no_useless_nullsafe_operator` fixer.
- `operator_linebreak` fixer.
- `php_unit_fqcn_annotation` fixer.
- `php_unit_test_case_static_method_calls` fixer.
- `simplified_null_return` fixer.
- `no_empty_statement` fixer.
- `no_singleline_whitespace_before_semicolons` fixer.
- `semicolon_after_instruction` fixer.
- `types_spaces` fixer.
- `no_trailing_comma_in_singleline` fixer.
- `no_useless_concat_operator` fixer.
### Changed
- `friendsofphp/php-cs-fixer` version bumped to `^3`.
- `braces` fixer now enables rule `allow_single_line_anonymous_class_with_empty_body`.
- `class_attributes_separation` fixer now fixes `const` in the `only_if_meta` mode.
### Removed
- `Ely/new_with_braces` since all its functionality is now included in the original fixer.
- `self_accessor` fixer because it leads to errors in interfaces, that returns self.
## [0.3.0] - 2019-02-23
### Added
- `array_indentation` fixer.
- `combine_consecutive_issets` fixer.
- `combine_nested_dirname` fixer.
- `dir_constant` fixer.
- `ereg_to_preg` fixer.
- `explicit_string_variable` fixer.
- `implode_call` fixer.
- `is_null` fixer.
- `list_syntax` fixer.
- `logical_operators` fixer.
- `lowercase_cast` fixer.
- `lowercase_static_reference` fixer.
- `magic_constant_casing` fixer.
- `magic_method_casing` fixer.
- `multiline_whitespace_before_semicolons` fixer.
- `native_function_casing` fixer.
- `no_alternative_syntax` fixer.
- `no_homoglyph_names` fixer.
- `no_leading_import_slash` fixer.
- `no_leading_namespace_whitespace` fixer.
- `no_mixed_echo_print` fixer.
- `no_multiline_whitespace_around_double_arrow` fixer.
- `no_php4_constructor` fixer.
- `no_spaces_around_offset` fixer.
- `no_superfluous_elseif` fixer.
- `no_unneeded_control_parentheses` fixer.
- `no_useless_return` fixer.
- `php_unit_construct` fixer.
- `php_unit_expectation` fixer.
- `php_unit_method_casing` fixer.
- `php_unit_mock` fixer.
- `php_unit_namespaced` fixer.
- `php_unit_set_up_tear_down_visibility` fixer.
- `php_unit_strict` fixer.
- `pow_to_exponentiation` fixer.
- `psr4` fixer.
- `return_assignment` fixer.
- `random_api_migration` fixer.
- `self_accessor` fixer.
- `set_type_to_cast` fixer.
- `short_scalar_cast` fixer.
- `space_after_semicolon` fixer.
- `standardize_increment` fixer.
- `standardize_not_equals` fixer.
- `trim_array_spaces` fixer.
- `unary_operator_spaces` fixer.
### Changed
- `friendsofphp/php-cs-fixer` version bumped to `^2.13.0`.
### Fixed
- `ordered_imports` now has fixed order of import types.
## [0.2.1] - 2019-02-22
### Fixed
- Compatibility with the `friendsofphp/php-cs-fixer` version 2.13.3 and above.
## [0.2.0] - 2018-08-08
### Added
- Enh #4: `Ely\remove_class_name_method_usages` fixer.
- `array_syntax` fixer.
- This changelog file.
- Travis CI building.
### Changed
- `friendsofphp/php-cs-fixer` version bumped to `^2.12.2`.
- `phpunit/phpunit` downgraded to `^6.5.1` to be compatible with PHP 7.0.
### Fixed
- Bug #5: `Ely/line_break_after_statements` triggers error if statement doesn't have control brackets.
## 0.1.0 - 2018-04-17
### Added
- First release
[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/0.4.0...HEAD
[0.4.0]: https://github.com/elyby/php-code-style/compare/0.3.0...0.4.0
[0.3.0]: https://github.com/elyby/php-code-style/compare/0.2.1...0.3.0
[0.2.1]: https://github.com/elyby/php-code-style/compare/0.2.0...0.2.1
[0.2.0]: https://github.com/elyby/php-code-style/compare/0.1.0...0.2.0

View File

@ -1,8 +1,13 @@
# Ely.by PHP-CS-Fixer rules
Set of PHP-CS-Fixer rules used in development of Ely.by PHP projects. It's suited for PHP 7.1 and above.
Set of PHP-CS-Fixer rules used in development of Ely.by PHP projects. It's suited for PHP 7.4 and above.
You can use it as a ready-made set of rules or [just some of them](#using-our-fixers).
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Total Downloads][ico-downloads]][link-downloads]
[![Software License][ico-license]](LICENSE.md)
[![Build Status][ico-build-status]][link-build-status]
## Installation
First of all install Ely.by PHP-CS-Fixer rules via composer with
@ -12,7 +17,7 @@ First of all install Ely.by PHP-CS-Fixer rules via composer with
composer require --dev friendsofphp/php-cs-fixer ely/php-code-style
```
Then create file `.php-cs` with following contents:
Then create a file `.php-cs-fixer.php` with the following contents:
```php
<?php
@ -189,7 +194,7 @@ Ensure that a class body contains one blank line after its definition and before
**Configuration:**
* `apply_to_anonymous_classes` - should this fixer be applied to anonymous classes? If it is set to `false`, than
anonymous classes will be fixed to don't have empty lines around body. **Default**: `false`.
anonymous classes will be fixed to don't have empty lines around body. **Default**: `true`.
* `blank_lines_count` - adjusts an amount of the blank lines. **Default**: `1`.
@ -241,23 +246,28 @@ and `do-while`.
$c = 'next statement';
```
### `Ely/new_with_braces`
### `Ely/remove_class_name_method_usages` (Yii2)
This is the extended version of the original `new_with_braces` fixer. It allows you to remove braces around
an anonymous class declaration in a case when said class constructor doesn't contain any arguments.
Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84)
usages with native `::class` keyword, introduced in PHP 5.5.
```diff
--- Original
+++ New
@@ @@
<?php
-$a = new Foo;
+$a = new Foo();
-$b = new class() extends Foo {};
+$b = new class extends Foo {};
<?php
use common\models\User;
- $className = User::className();
+ $className = User::class;
```
**Configuration:**
[ico-version]: https://img.shields.io/packagist/v/ely/php-code-style.svg?style=flat-square
[ico-license]: https://img.shields.io/badge/license-Apache-green.svg?style=flat-square
[ico-downloads]: https://img.shields.io/packagist/dt/ely/php-code-style.svg?style=flat-square
[ico-build-status]: https://img.shields.io/github/workflow/status/elyby/php-code-style/CI.svg?style=flat-square
* `remove_for_anonymous_classes` - if its set to `true`, then braces for anonymous classes without constructor
arguments will be removed. **Default**: `false`.
[link-packagist]: https://packagist.org/packages/ely/php-code-style
[link-contributors]: ../../contributors
[link-downloads]: https://packagist.org/packages/ely/php-code-style/stats
[link-build-status]: https://github.com/elyby/php-code-style/actions

View File

@ -1,8 +1,12 @@
{
"name": "ely/php-code-style",
"description": "Set of PHP-CS-Fixer rules used in the development of Ely.by PHP projects",
"keywords": ["php-cs-fixer", "code style"],
"homepage": "https://github.com/elyby/php-code-style",
"license": "Apache-2.0",
"type": "library",
"keywords": [
"php-cs-fixer",
"code style"
],
"authors": [
{
"name": "Ely.by team",
@ -13,14 +17,20 @@
"email": "erickskrauch@ely.by"
}
],
"license": "Apache-2.0",
"type": "library",
"homepage": "https://github.com/elyby/php-code-style",
"require": {
"php": "^7.0",
"friendsofphp/php-cs-fixer": "^2.11"
"php": "^7.4 || ^8.0",
"friendsofphp/php-cs-fixer": "^3.13"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
"ergebnis/composer-normalize": "^2.28",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2",
"phpspec/prophecy": "^1.15",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"phpunitgoodpractices/polyfill": "^1.5",
"phpunitgoodpractices/traits": "^1.9.1",
"symfony/phpunit-bridge": "^6.0"
},
"autoload": {
"psr-4": {
@ -29,10 +39,16 @@
},
"autoload-dev": {
"psr-4": {
"Ely\\CS\\Test\\": "tests/"
"Ely\\CS\\Test\\": "tests/",
"PhpCsFixer\\Tests\\": "vendor/friendsofphp/php-cs-fixer/tests/"
}
},
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true
},
"files": [
"vendor/friendsofphp/php-cs-fixer/tests/Test/Constraint/SameStringsConstraint.php"
]
"preferred-install": {
"friendsofphp/php-cs-fixer": "source"
}
}
}

3800
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,34 +3,25 @@
<phpunit
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestSize="true"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutTodoAnnotatedTests="true"
bootstrap="./vendor/autoload.php"
colors="true"
columns="max"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
verbose="true"
>
<testsuites>
<testsuite>
<testsuite name="all">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<coverage>
<include>
<directory>./src</directory>
</whitelist>
</filter>
</include>
</coverage>
<php>
<ini name="zend.enable_gc" value="0"/>

View File

@ -8,7 +8,7 @@ use PhpCsFixer\Config as PhpCsFixerConfig;
class Config {
public static function create(array $overwrittenRules = []): PhpCsFixerConfig {
return PhpCsFixerConfig::create()
return (new PhpCsFixerConfig())
->setRiskyAllowed(true)
->registerCustomFixers(new Fixers())
->setRules(Rules::create($overwrittenRules));

View File

@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Fixer;
abstract class AbstractFixer extends \PhpCsFixer\AbstractFixer {
@ -6,7 +8,7 @@ abstract class AbstractFixer extends \PhpCsFixer\AbstractFixer {
/**
* {@inheritdoc}
*/
public function getName() {
public function getName(): string {
return sprintf('Ely/%s', parent::getName());
}

View File

@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Fixer\LanguageConstruct;
use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use SplFileInfo;
/**
* Replaces Yii2 BaseObject::className() usages with native ::class keyword, introduced in PHP 5.5.
*
* @author ErickSkrauch <erickskrauch@ely.by>
*/
final class RemoveClassNameMethodUsagesFixer extends AbstractFixer {
public function getDefinition(): FixerDefinitionInterface {
return new FixerDefinition(
'Converts Yii2 `BaseObject::className()` method usage into `::class` keyword.',
[
new CodeSample(
'<?php
use Foo\Bar\Baz;
$className = Baz::className();
',
),
],
null,
'Risky when the method `className()` is overridden.',
);
}
public function isCandidate(Tokens $tokens): bool {
return $tokens->isTokenKindFound(T_STRING);
}
public function isRisky(): bool {
return true;
}
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
for ($index = $tokens->count() - 4; $index > 0; --$index) {
$candidate = $this->getReplaceCandidate($tokens, $index);
if ($candidate === null) {
continue;
}
$this->fixClassNameMethodUsage(
$tokens,
$index,
$candidate[0], // brace open
$candidate[1], // brace close
);
}
}
private function getReplaceCandidate(Tokens $tokens, int $index): ?array {
if (!$tokens[$index]->isGivenKind(T_STRING)) {
return null;
}
$braceOpenIndex = $tokens->getNextMeaningfulToken($index);
if (!$tokens[$braceOpenIndex]->equals('(')) {
return null;
}
$braceCloseIndex = $tokens->getNextMeaningfulToken($braceOpenIndex);
if (!$tokens[$braceCloseIndex]->equals(')')) {
return null;
}
$doubleColon = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$doubleColon]->isGivenKind([T_DOUBLE_COLON])) {
return null;
}
$methodName = $tokens[$index]->getContent();
if ($methodName !== 'className') {
return null;
}
return [
$braceOpenIndex,
$braceCloseIndex,
];
}
private function fixClassNameMethodUsage(
Tokens $tokens,
int $index,
int $braceOpenIndex,
int $braceCloseIndex
): void {
$tokens->clearTokenAndMergeSurroundingWhitespace($braceCloseIndex);
$tokens->clearTokenAndMergeSurroundingWhitespace($braceOpenIndex);
$tokens->clearAt($index);
$tokens->insertAt($index, new Token([CT::T_CLASS_CONSTANT, 'class']));
}
}

View File

@ -1,179 +0,0 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Fixer\Operator;
use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* This is the extended version of the original new_with_braces fixer.
* It allows you to remove braces around an anonymous class declaration in a case
* when said class constructor doesn't contain any arguments.
*
* @url https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/5c5de791ab/src/Fixer/Operator/NewWithBracesFixer.php
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class NewWithBracesFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface {
/**
* {@inheritdoc}
*/
public function getDefinition() {
return new FixerDefinition(
'All instances created with new keyword must be followed by braces.',
[
new CodeSample("<?php \$x = new X;\n"),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens) {
return $tokens->isTokenKindFound(T_NEW);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens) {
static $nextTokenKinds = null;
if ($nextTokenKinds === null) {
$nextTokenKinds = [
'?',
';',
',',
'(',
')',
'[',
']',
':',
'<',
'>',
'+',
'-',
'*',
'/',
'%',
'&',
'^',
'|',
[T_CLASS],
[T_IS_SMALLER_OR_EQUAL],
[T_IS_GREATER_OR_EQUAL],
[T_IS_EQUAL],
[T_IS_NOT_EQUAL],
[T_IS_IDENTICAL],
[T_IS_NOT_IDENTICAL],
[T_CLOSE_TAG],
[T_LOGICAL_AND],
[T_LOGICAL_OR],
[T_LOGICAL_XOR],
[T_BOOLEAN_AND],
[T_BOOLEAN_OR],
[T_SL],
[T_SR],
[T_INSTANCEOF],
[T_AS],
[T_DOUBLE_ARROW],
[T_POW],
[CT::T_ARRAY_SQUARE_BRACE_OPEN],
[CT::T_ARRAY_SQUARE_BRACE_CLOSE],
[CT::T_BRACE_CLASS_INSTANTIATION_OPEN],
[CT::T_BRACE_CLASS_INSTANTIATION_CLOSE],
];
if (defined('T_SPACESHIP')) {
$nextTokenKinds[] = [T_SPACESHIP];
}
}
for ($index = $tokens->count() - 3; $index > 0; --$index) {
$token = $tokens[$index];
if (!$token->isGivenKind(T_NEW)) {
continue;
}
$nextIndex = $tokens->getNextTokenOfKind($index, $nextTokenKinds);
$nextToken = $tokens[$nextIndex];
// new anonymous class definition
if ($nextToken->isGivenKind(T_CLASS)) {
if ($this->configuration['remove_for_anonymous_classes']) {
$nextTokenIndex = $tokens->getNextMeaningfulToken($nextIndex);
$nextNextTokenIndex = $tokens->getNextMeaningfulToken($nextTokenIndex);
if ($tokens[$nextTokenIndex]->equals('(') && $tokens[$nextNextTokenIndex]->equals(')')) {
$this->removeBracesAfter($tokens, $nextIndex);
}
} else {
if (!$tokens[$tokens->getNextMeaningfulToken($nextIndex)]->equals('(')) {
$this->insertBracesAfter($tokens, $nextIndex);
}
}
continue;
}
// entrance into array index syntax - need to look for exit
while ($nextToken->equals('[')) {
$nextIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $nextIndex) + 1;
$nextToken = $tokens[$nextIndex];
}
// new statement has a gap in it - advance to the next token
if ($nextToken->isWhitespace()) {
$nextIndex = $tokens->getNextNonWhitespace($nextIndex);
$nextToken = $tokens[$nextIndex];
}
// new statement with () - nothing to do
if ($nextToken->equals('(')) {
continue;
}
$this->insertBracesAfter($tokens, $tokens->getPrevMeaningfulToken($nextIndex));
}
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition() {
return new FixerConfigurationResolver([
(new FixerOptionBuilder('remove_for_anonymous_classes', 'when enabled will remove braces around an anonymous class declaration in a case when constructor doesn\'t contain any arguments'))
->setAllowedTypes(['bool'])
->setDefault(false)
->getOption(),
]);
}
/**
* @param Tokens $tokens
* @param int $index
*/
private function insertBracesAfter(Tokens $tokens, $index) {
$tokens->insertAt(++$index, [new Token('('), new Token(')')]);
}
/**
* @param Tokens $tokens
* @param int $index
*/
private function removeBracesAfter(Tokens $tokens, int $index) {
$tokens->clearRange(
$tokens->getNextTokenOfKind($index, ['(']),
$tokens->getNextTokenOfKind($index, [')'])
);
}
}

View File

@ -4,28 +4,27 @@ declare(strict_types=1);
namespace Ely\CS\Fixer\Whitespace;
use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
use PhpCsFixer\Utils;
/**
* This is copy of the PR https://github.com/FriendsOfPHP/PHP-CS-Fixer/pull/3688
*
* @author ErickSkrauch <erickskrauch@ely.by>
*/
final class BlankLineAroundClassBodyFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface {
final class BlankLineAroundClassBodyFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface {
/**
* {@inheritdoc}
*/
public function getDefinition() {
public function getDefinition(): FixerDefinitionInterface {
return new FixerDefinition(
'Ensure that class body contains one blank line after class definition and before its end.',
[
@ -37,7 +36,7 @@ class Sample
{
}
}
'
',
),
new CodeSample(
'<?php
@ -49,7 +48,7 @@ new class extends Foo {
};
',
['apply_to_anonymous_classes' => false]
['apply_to_anonymous_classes' => false],
),
new CodeSample(
'<?php
@ -59,31 +58,22 @@ new class extends Foo {
}
};
',
['apply_to_anonymous_classes' => true]
['apply_to_anonymous_classes' => true],
),
]
],
);
}
/**
* {@inheritdoc}
*/
public function getPriority() {
public function getPriority(): int {
// should be run after the BracesFixer
return -26;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens) {
public function isCandidate(Tokens $tokens): bool {
return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens) {
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void {
$analyzer = new TokensAnalyzer($tokens);
foreach ($tokens as $index => $token) {
if (!$token->isClassy()) {
@ -111,10 +101,7 @@ new class extends Foo {
}
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition() {
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface {
return new FixerConfigurationResolver([
(new FixerOptionBuilder('blank_lines_count', 'adjusts an amount of the blank lines.'))
->setAllowedTypes(['int'])
@ -127,14 +114,7 @@ new class extends Foo {
]);
}
/**
* Cleanup a whitespace token.
*
* @param Tokens $tokens
* @param int $index
* @param int $countLines
*/
private function fixBlankLines(Tokens $tokens, $index, $countLines) {
private function fixBlankLines(Tokens $tokens, int $index, int $countLines): void {
$content = $tokens[$index]->getContent();
// Apply fix only in the case when the count lines do not equals to expected
if (substr_count($content, "\n") === $countLines + 1) {
@ -142,7 +122,8 @@ new class extends Foo {
}
// The final bit of the whitespace must be the next statement's indentation
$lines = Utils::splitLines($content);
Preg::matchAll('/[^\n\r]+[\r\n]*/', $content, $matches);
$lines = $matches[0];
$eol = $this->whitespacesConfig->getLineEnding();
$tokens[$index] = new Token([T_WHITESPACE, str_repeat($eol, $countLines + 1) . end($lines)]);
}

View File

@ -7,6 +7,7 @@ use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use SplFileInfo;
@ -23,35 +24,23 @@ use SplFileInfo;
*/
final class BlankLineBeforeReturnFixer extends AbstractFixer implements WhitespacesAwareFixerInterface {
/**
* {@inheritdoc}
*/
public function getDefinition() {
public function getDefinition(): FixerDefinitionInterface {
return new FixerDefinition(
'An empty line feed should precede a return statement.',
[new CodeSample("<?php\nfunction A()\n{\n echo 1;\n return 1;\n}\n")]
[new CodeSample("<?php\nfunction A()\n{\n echo 1;\n echo 2;\n return 1;\n}\n")],
);
}
/**
* @inheritdoc
*/
public function isCandidate(Tokens $tokens) {
public function isCandidate(Tokens $tokens): bool {
return $tokens->isTokenKindFound(T_RETURN);
}
/**
* {@inheritdoc}
*/
public function getPriority() {
public function getPriority(): int {
// should be run after NoUselessReturnFixer, ClassDefinitionFixer and BracesFixer
return -26;
}
/**
* @inheritdoc
*/
protected function applyFix(SplFileInfo $file, Tokens $tokens) {
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
$token = $tokens[$index];
if (!$token->isGivenKind(T_RETURN)) {
@ -93,7 +82,7 @@ final class BlankLineBeforeReturnFixer extends AbstractFixer implements Whitespa
}
}
} else {
$tokens->insertAt($index, new Token([T_WHITESPACE, $eol . $eol]));
$tokens->insertSlices([$index => new Token([T_WHITESPACE, $eol . $eol])]);
++$index;
++$limit;
}

View File

@ -7,9 +7,10 @@ use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Utils;
use SplFileInfo;
/**
@ -25,7 +26,7 @@ final class LineBreakAfterStatementsFixer extends AbstractFixer implements White
/**
* There is no 'do', 'cause the processing of the 'while' also includes do {} while (); construction
*/
const STATEMENTS = [
public const STATEMENTS = [
T_IF,
T_SWITCH,
T_FOR,
@ -33,12 +34,9 @@ final class LineBreakAfterStatementsFixer extends AbstractFixer implements White
T_WHILE,
];
/**
* @inheritdoc
*/
public function getDefinition() {
public function getDefinition(): FixerDefinitionInterface {
return new FixerDefinition(
'Ensures that there is one blank line above the control statements',
'Ensures that there is one blank line above the control statements.',
[
new CodeSample(
'<?php
@ -73,20 +71,22 @@ class Foo
$a = "next statement";
}
}
'
',
),
]
],
);
}
/**
* @inheritdoc
*/
public function isCandidate(Tokens $tokens) {
public function isCandidate(Tokens $tokens): bool {
return $tokens->isAnyTokenKindsFound(self::STATEMENTS);
}
protected function applyFix(SplFileInfo $file, Tokens $tokens) {
public function getPriority(): int {
// for the best result should be run after the BracesFixer
return -26;
}
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
foreach ($tokens as $index => $token) {
if (!$token->isGivenKind(self::STATEMENTS)) {
continue;
@ -107,7 +107,7 @@ class Foo
}
}
private function fixBlankLines(Tokens $tokens, $index, $countLines) {
private function fixBlankLines(Tokens $tokens, int $index, int $countLines): void {
$content = $tokens[$index]->getContent();
// Apply fix only in the case when the count lines do not equals to expected
if (substr_count($content, "\n") === $countLines + 1) {
@ -115,7 +115,8 @@ class Foo
}
// The final bit of the whitespace must be the next statement's indentation
$lines = Utils::splitLines($content);
Preg::matchAll('/[^\n\r]+[\r\n]*/', $content, $matches);
$lines = $matches[0];
$eol = $this->whitespacesConfig->getLineEnding();
$tokens[$index] = new Token([T_WHITESPACE, str_repeat($eol, $countLines + 1) . end($lines)]);
}
@ -126,17 +127,23 @@ class Foo
if ($nextToken->equals('(')) {
$parenthesisEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
$possibleStartBraceIndex = $tokens->getNextNonWhitespace($parenthesisEndIndex);
$possibleBeginBraceIndex = $tokens->getNextNonWhitespace($parenthesisEndIndex);
} else {
$possibleStartBraceIndex = $nextIndex;
$possibleBeginBraceIndex = $nextIndex;
}
// `do {} while ();`
if ($tokens[$index]->isGivenKind(T_WHILE) && $tokens[$possibleStartBraceIndex]->equals(';')) {
return $possibleStartBraceIndex;
if ($tokens[$index]->isGivenKind(T_WHILE) && $tokens[$possibleBeginBraceIndex]->equals(';')) {
return $possibleBeginBraceIndex;
}
$possibleBeginBrace = $tokens[$possibleBeginBraceIndex];
if ($possibleBeginBrace->equals('{')) {
$blockEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $possibleBeginBraceIndex);
} else {
$blockEnd = $tokens->getNextTokenOfKind($possibleBeginBraceIndex, [';']);
}
$blockEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $possibleStartBraceIndex);
$nextStatementIndex = $tokens->getNextMeaningfulToken($blockEnd);
if ($nextStatementIndex === null) {
return $blockEnd;

View File

@ -22,7 +22,6 @@ class Fixers implements IteratorAggregate {
continue;
}
/** @noinspection PhpUnhandledExceptionInspection */
$rfl = new ReflectionClass($class);
if (!$rfl->implementsInterface(FixerInterface::class) || $rfl->isAbstract()) {
continue;
@ -31,9 +30,7 @@ class Fixers implements IteratorAggregate {
$classes[] = $class;
}
return new ArrayIterator(array_map(function($class) {
return new $class();
}, $classes));
return new ArrayIterator(array_map(fn($class) => new $class(), $classes));
}
}

View File

@ -5,70 +5,222 @@ namespace Ely\CS;
class Rules {
private static $rules = [
'@PSR2' => true,
'binary_operator_spaces' => true,
'braces' => [
'position_after_functions_and_oop_constructs' => 'same',
],
'cast_spaces' => [
'space' => 'none',
],
'class_attributes_separation' => [
'elements' => ['method', 'property'],
],
'compact_nullable_typehint' => true,
'concat_space' => [
'spacing' => 'one',
],
'declare_equal_normalize' => true,
'function_declaration' => [
'closure_function_spacing' => 'none',
],
'function_to_constant' => true,
'include' => true,
'linebreak_after_opening_tag' => true,
'method_chaining_indentation' => true,
'modernize_types_casting' => true,
'no_short_bool_cast' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_final_method' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'non_printable_character' => [
'use_escape_sequences_in_strings' => true,
],
'object_operator_without_whitespace' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'random_api_migration' => true,
'return_type_declaration' => [
'space_before' => 'none',
],
'single_quote' => true,
'strict_comparison' => true,
'ternary_operator_spaces' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline_array' => true,
'visibility_required' => [
'elements' => ['property', 'method', 'const'],
],
'whitespace_after_comma_in_array' => true,
// Our custom or extended fixers
'Ely/blank_line_around_class_body' => [
'apply_to_anonymous_classes' => false,
],
'Ely/blank_line_before_return' => true,
'Ely/line_break_after_statements' => true,
'Ely/new_with_braces' => [
'remove_for_anonymous_classes' => true,
],
];
public static function create(array $overwrittenRules = []): array {
return array_merge(self::$rules, $overwrittenRules);
return array_merge([
'@PSR2' => true,
// Alias
'ereg_to_preg' => true,
'modernize_strpos' => PHP_MAJOR_VERSION >= 8,
'no_mixed_echo_print' => true,
'pow_to_exponentiation' => true,
'random_api_migration' => [
'replacements' => [
'getrandmax' => 'mt_getrandmax',
'rand' => 'random_int',
'srand' => 'mt_srand',
],
],
'set_type_to_cast' => true,
// Array Notation
'array_syntax' => [
'syntax' => 'short',
],
'no_multiline_whitespace_around_double_arrow' => true,
'no_whitespace_before_comma_in_array' => true,
'normalize_index_brace' => true,
'trim_array_spaces' => true,
'whitespace_after_comma_in_array' => true,
// Basic
'braces' => [
'allow_single_line_anonymous_class_with_empty_body' => true,
'position_after_functions_and_oop_constructs' => 'same',
],
'no_multiple_statements_per_line' => true,
'no_trailing_comma_in_singleline' => true,
'non_printable_character' => [
'use_escape_sequences_in_strings' => true,
],
'octal_notation' => PHP_MAJOR_VERSION >= 8 && PHP_MINOR_VERSION >= 1,
'psr_autoloading' => true,
// Casing
'class_reference_name_casing' => true,
'integer_literal_case' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'native_function_casing' => true,
'native_function_type_declaration_casing' => true,
// Cast Notation
'cast_spaces' => [
'space' => 'none',
],
'lowercase_cast' => true,
'modernize_types_casting' => true,
'no_short_bool_cast' => true,
'no_unset_cast' => true,
'short_scalar_cast' => true,
// Class Notation
'class_attributes_separation' => [
'elements' => [
'method' => 'one',
'property' => 'one',
],
],
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_unneeded_final_method' => true,
'ordered_class_elements' => true,
'single_trait_insert_per_statement' => true,
'visibility_required' => true,
// Comment
'comment_to_phpdoc' => true,
'multiline_comment_opening_closing' => true,
'no_empty_comment' => true,
'single_line_comment_spacing' => true,
'single_line_comment_style' => true,
// Control Structure
'empty_loop_body' => true,
'empty_loop_condition' => true,
'include' => true,
'no_alternative_syntax' => true,
'no_superfluous_elseif' => true,
'no_unneeded_control_parentheses' => true,
'no_useless_else' => true,
'switch_continue_to_break' => true,
'trailing_comma_in_multiline' => [
'elements' => PHP_MAJOR_VERSION >= 8
? ['arrays', 'arguments', 'parameters', 'match']
: ['arrays', 'arguments'],
],
'yoda_style' => [
'equal' => false,
'identical' => false,
'less_and_greater' => false,
],
// Function Notation
'combine_nested_dirname' => true,
'function_declaration' => [
'closure_function_spacing' => 'none',
'closure_fn_spacing' => 'none',
],
'function_typehint_space' => true,
'implode_call' => true,
'lambda_not_used_import' => true,
'return_type_declaration' => true,
// Import
'no_leading_import_slash' => true,
'no_unneeded_import_alias' => true,
'no_unused_imports' => true,
'ordered_imports' => [
'imports_order' => ['class', 'function', 'const'],
],
// Language Construct
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'declare_equal_normalize' => true,
'declare_parentheses' => true,
'dir_constant' => true,
'function_to_constant' => true,
'is_null' => true,
// List Notation
'list_syntax' => true,
// Namespace Notation
'clean_namespace' => true,
'no_leading_namespace_whitespace' => true,
// Naming
'no_homoglyph_names' => true,
// Operator
'assign_null_coalescing_to_coalesce_equal' => true,
'binary_operator_spaces' => true,
'concat_space' => [
'spacing' => 'one',
],
'logical_operators' => true,
'new_with_braces' => [
'anonymous_class' => false,
],
'no_useless_concat_operator' => true,
'no_useless_nullsafe_operator' => true,
'object_operator_without_whitespace' => true,
'operator_linebreak' => true,
'standardize_increment' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'ternary_to_null_coalescing' => true,
'unary_operator_spaces' => true,
// PHP Tag
'linebreak_after_opening_tag' => true,
// PHPUnit
'php_unit_construct' => true,
'php_unit_dedicate_assert_internal_type' => true,
'php_unit_expectation' => true,
'php_unit_fqcn_annotation' => true,
'php_unit_method_casing' => true,
'php_unit_mock' => true,
'php_unit_mock_short_will_return' => true,
'php_unit_namespaced' => true,
'php_unit_no_expectation_annotation' => true,
'php_unit_set_up_tear_down_visibility' => true,
'php_unit_strict' => true,
'php_unit_test_case_static_method_calls' => [
'call_type' => 'this',
],
// Return Notation
'no_useless_return' => true,
'return_assignment' => true,
'simplified_null_return' => true,
// Semicolon
'multiline_whitespace_before_semicolons' => true,
'no_empty_statement' => true,
'no_singleline_whitespace_before_semicolons' => true,
'semicolon_after_instruction' => true,
'space_after_semicolon' => true,
// Strict
'strict_comparison' => true,
// String notation
'explicit_string_variable' => true,
'simple_to_complex_string_variable' => true,
'single_quote' => true,
// Whitespace
'array_indentation' => true,
'compact_nullable_typehint' => true,
'method_chaining_indentation' => true,
'no_spaces_around_offset' => true,
'no_whitespace_in_blank_line' => true,
'types_spaces' => [
'space_multiple_catch' => 'none',
],
// Our custom or extended fixers
'Ely/blank_line_around_class_body' => [
'apply_to_anonymous_classes' => false,
],
'Ely/blank_line_before_return' => true,
'Ely/line_break_after_statements' => true,
'Ely/remove_class_name_method_usages' => true,
], $overwrittenRules);
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Test\Fixer\LanguageConstruct;
use Ely\CS\Fixer\LanguageConstruct\RemoveClassNameMethodUsagesFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
/**
* @covers \Ely\CS\Fixer\LanguageConstruct\RemoveClassNameMethodUsagesFixer
*/
class RemoveClassNameMethodUsagesFixerTest extends AbstractFixerTestCase {
/**
* @dataProvider provideFixCases
*/
public function testFix(string $expected, ?string $input = null): void {
$this->doTest($expected, $input);
}
public function provideFixCases(): iterable {
yield [
'<?php echo className();',
];
yield [
'<?php
use Foo\Bar\Baz;
$exceptionString = Baz::classname();
',
];
yield [
'<?php
use Foo\Bar\Baz;
$className = Baz::class;
',
'<?php
use Foo\Bar\Baz;
$className = Baz::className();
',
];
yield [
'<?php
use Foo\Bar\Baz;
$exceptionString = "The class should be instance of " . Baz::class . " and nothing else";
',
'<?php
use Foo\Bar\Baz;
$exceptionString = "The class should be instance of " . Baz::className() . " and nothing else";
',
];
}
protected function createFixer(): AbstractFixer {
return new RemoveClassNameMethodUsagesFixer();
}
}

View File

@ -1,319 +0,0 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Test\Fixer\Operator;
use Ely\CS\Fixer\Operator\NewWithBracesFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
/**
* Original file copied from:
* @url https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/5c5de791ab/tests/Fixer/Operator/NewWithBracesFixerTest.php
*
* @covers \Ely\CS\Fixer\Operator\NewWithBracesFixer
*/
class NewWithBracesFixerTest extends AbstractFixerTestCase {
private static $removeForAnonymousClasses = ['remove_for_anonymous_classes' => true];
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideFixCases
*/
public function testFix($expected, $input = null) {
$this->doTest($expected, $input);
}
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideFix70Cases
* @requires PHP 7.0
*/
public function testFix70($expected, $input = null, array $configuration = null) {
if ($configuration !== null) {
$this->fixer->configure($configuration);
}
$this->doTest($expected, $input);
}
public function provideFixCases() {
return [
[
'<?php class A { public function B(){ $static = new static(new \SplFileInfo(__FILE__)); }}',
],
[
'<?php $static = new self(new \SplFileInfo(__FILE__));',
],
[
'<?php $x = new X/**/ /**/ /**//**//**/ /**//**/ (/**/ /**/ /**//**//**/ /**//**/)/**/ /**/ /**//**//**/ /**//**/;/**/ /**/ /**//**//**/ /**//**/',
],
[
'<?php $x = new X();',
'<?php $x = new X;',
],
[
'<?php $y = new Y() ;',
'<?php $y = new Y ;',
],
[
'<?php $x = new Z() /**/;//',
'<?php $x = new Z /**/;//',
],
[
'<?php $foo = new $foo();',
'<?php $foo = new $foo;',
],
[
'<?php $xyz = new X(new Y(new Z()));',
'<?php $xyz = new X(new Y(new Z));',
],
[
'<?php $foo = (new $bar())->foo;',
'<?php $foo = (new $bar)->foo;',
],
[
'<?php $foo = (new $bar((new Foo())->bar))->foo;',
'<?php $foo = (new $bar((new Foo)->bar))->foo;',
],
[
'<?php $self = new self();',
'<?php $self = new self;',
],
[
'<?php $static = new static();',
'<?php $static = new static;',
],
[
'<?php $a = array( "key" => new DateTime(), );',
'<?php $a = array( "key" => new DateTime, );',
],
[
'<?php $a = array( "key" => new DateTime() );',
'<?php $a = array( "key" => new DateTime );',
],
[
'<?php $a = new $b[$c]();',
'<?php $a = new $b[$c];',
],
[
'<?php $a = new $b[$c[$d ? foo() : bar("bar[...]") - 1]]();',
'<?php $a = new $b[$c[$d ? foo() : bar("bar[...]") - 1]];',
],
[
'<?php $a = new $b[\'class\']();',
'<?php $a = new $b[\'class\'];',
],
[
'<?php $a = new $b[\'class\'] ($foo[\'bar\']);',
],
[
'<?php $a = new $b[\'class\'] () ;',
],
[
'<?php $a = new $b[$c] ($hello[$world]) ;',
],
[
"<?php \$a = new \$b['class']()\r\n\t ;",
"<?php \$a = new \$b['class']\r\n\t ;",
],
[
'<?php $a = $b ? new DateTime() : $b;',
'<?php $a = $b ? new DateTime : $b;',
],
[
'<?php new self::$adapters[$name]["adapter"]();',
'<?php new self::$adapters[$name]["adapter"];',
],
[
'<?php $a = new \Exception()?> <?php echo 1;',
'<?php $a = new \Exception?> <?php echo 1;',
],
[
'<?php $b = new \StdClass() /**/?>',
'<?php $b = new \StdClass /**/?>',
],
[
'<?php $a = new Foo() instanceof Foo;',
'<?php $a = new Foo instanceof Foo;',
],
[
'<?php
$a = new Foo() + 1;
$a = new Foo() - 1;
$a = new Foo() * 1;
$a = new Foo() / 1;
$a = new Foo() % 1;
',
'<?php
$a = new Foo + 1;
$a = new Foo - 1;
$a = new Foo * 1;
$a = new Foo / 1;
$a = new Foo % 1;
',
],
[
'<?php
$a = new Foo() & 1;
$a = new Foo() | 1;
$a = new Foo() ^ 1;
$a = new Foo() << 1;
$a = new Foo() >> 1;
',
'<?php
$a = new Foo & 1;
$a = new Foo | 1;
$a = new Foo ^ 1;
$a = new Foo << 1;
$a = new Foo >> 1;
',
],
[
'<?php
$a = new Foo() and 1;
$a = new Foo() or 1;
$a = new Foo() xor 1;
$a = new Foo() && 1;
$a = new Foo() || 1;
',
'<?php
$a = new Foo and 1;
$a = new Foo or 1;
$a = new Foo xor 1;
$a = new Foo && 1;
$a = new Foo || 1;
',
],
[
'<?php
if (new DateTime() > $this->startDate) {}
if (new DateTime() >= $this->startDate) {}
if (new DateTime() < $this->startDate) {}
if (new DateTime() <= $this->startDate) {}
if (new DateTime() == $this->startDate) {}
if (new DateTime() != $this->startDate) {}
if (new DateTime() <> $this->startDate) {}
if (new DateTime() === $this->startDate) {}
if (new DateTime() !== $this->startDate) {}
',
'<?php
if (new DateTime > $this->startDate) {}
if (new DateTime >= $this->startDate) {}
if (new DateTime < $this->startDate) {}
if (new DateTime <= $this->startDate) {}
if (new DateTime == $this->startDate) {}
if (new DateTime != $this->startDate) {}
if (new DateTime <> $this->startDate) {}
if (new DateTime === $this->startDate) {}
if (new DateTime !== $this->startDate) {}
',
],
[
'<?php $a = new \stdClass() ? $b : $c;',
'<?php $a = new \stdClass ? $b : $c;',
],
[
'<?php foreach (new Collection() as $x) {}',
'<?php foreach (new Collection as $x) {}',
],
[
'<?php $a = [(string) new Foo() => 1];',
'<?php $a = [(string) new Foo => 1];',
],
[
'<?php $a = [ "key" => new DateTime(), ];',
'<?php $a = [ "key" => new DateTime, ];',
],
[
'<?php $a = [ "key" => new DateTime() ];',
'<?php $a = [ "key" => new DateTime ];',
],
[
'<?php
$a = new Foo() ** 1;
',
'<?php
$a = new Foo ** 1;
',
],
];
}
public function provideFix70Cases() {
return [
[
'<?php
$a = new Foo() <=> 1;
',
'<?php
$a = new Foo <=> 1;
',
],
[
'<?php
$a = new class() {use SomeTrait;};
$a = new class() implements Foo{};
$a = new class() /**/ extends Bar1{};
$a = new class() extends Bar2 implements Foo{};
$a = new class() extends Bar3 implements Foo, Foo2{};
$a = new class() {}?>
',
'<?php
$a = new class {use SomeTrait;};
$a = new class implements Foo{};
$a = new class /**/ extends Bar1{};
$a = new class extends Bar2 implements Foo{};
$a = new class extends Bar3 implements Foo, Foo2{};
$a = new class {}?>
',
],
[
'<?php
class A {
public function B() {
$static = new static(new class(){});
}
}
',
'<?php
class A {
public function B() {
$static = new static(new class{});
}
}
',
],
[
'<?php
$a = new class {use SomeTrait;};
$a = new class implements Foo{};
$a = new class /**/ extends Bar1{};
$a = new class extends Bar2 implements Foo{};
$a = new class extends Bar3 implements Foo, Foo2{};
$a = new class {};
$a = new class {};
',
'<?php
$a = new class() {use SomeTrait;};
$a = new class() implements Foo{};
$a = new class() /**/ extends Bar1{};
$a = new class() extends Bar2 implements Foo{};
$a = new class() extends Bar3 implements Foo, Foo2{};
$a = new class() {};
$a = new class( ) {};
',
self::$removeForAnonymousClasses,
],
];
}
protected function createFixer() {
return new NewWithBracesFixer();
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Ely\CS\Test\Fixer\Whitespace;
use Ely\CS\Fixer\Whitespace\BlankLineAroundClassBodyFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
use PhpCsFixer\WhitespacesFixerConfig;
@ -19,40 +20,18 @@ final class BlankLineAroundClassBodyFixerTest extends AbstractFixerTestCase {
private static $configurationTwoEmptyLines = ['blank_lines_count' => 2];
/**
* @param string $expected
* @param null|string $input
* @param null|array $configuration
*
* @dataProvider provideFixCases
*/
public function testFix($expected, $input = null, array $configuration = null) {
if (null !== $configuration) {
public function testFix(string $expected, ?string $input = null, array $configuration = null): void {
if ($configuration !== null) {
$this->fixer->configure($configuration);
}
$this->doTest($expected, $input);
}
/**
* @param string $expected
* @param null|string $input
* @param array $configuration
*
* @dataProvider provideAnonymousClassesCases
* @requires PHP 7.0
*/
public function testFixAnonymousClasses($expected, $input = null, array $configuration = null) {
if (null !== $configuration) {
$this->fixer->configure($configuration);
}
$this->doTest($expected, $input);
}
public function provideFixCases() {
$cases = [];
$cases[] = [
public function provideFixCases(): iterable {
yield [
'<?php
class Good
{
@ -72,7 +51,8 @@ class Good
}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -98,7 +78,8 @@ class Good
}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -130,7 +111,8 @@ class Good
}',
];
$cases[] = [
yield [
'<?php
interface Good
{
@ -150,7 +132,8 @@ interface Good
public function firstMethod();
}',
];
$cases[] = [
yield [
'<?php
trait Good
{
@ -170,7 +153,8 @@ trait Good
public function firstMethod() {}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -193,7 +177,8 @@ class Good
}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -218,7 +203,8 @@ class Good
}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -247,7 +233,8 @@ class Good
}
}',
];
$cases[] = [
yield [
'<?php
class Good
{
@ -272,7 +259,7 @@ class Good
];
// check if some fancy whitespaces aren't modified
$cases[] = [
yield [
'<?php
class Good
{public
@ -287,13 +274,7 @@ class Good
}',
];
return $cases;
}
public function provideAnonymousClassesCases() {
$cases = [];
$cases[] = [
yield [
'<?php
$class = new class extends \Foo {
@ -309,7 +290,8 @@ $class = new class extends \Foo {
public function firstMethod() {}
};',
];
$cases[] = [
yield [
'<?php
$class = new class extends \Foo {
public $field;
@ -326,17 +308,12 @@ $class = new class extends \Foo {
};',
self::$configurationDoNotApplyForAnonymousClasses,
];
return $cases;
}
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideMessyWhitespacesCases
*/
public function testMessyWhitespaces($expected, $input = null) {
public function testMessyWhitespaces(string $expected, ?string $input = null): void {
/** @var \PhpCsFixer\Fixer\WhitespacesAwareFixerInterface $fixer */
$fixer = $this->fixer;
$fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
@ -344,20 +321,19 @@ $class = new class extends \Foo {
$this->doTest($expected, $input);
}
public function provideMessyWhitespacesCases() {
return [
[
"<?php\nclass Foo\n{\r\n\r\n public function bar() {}\r\n\r\n}",
"<?php\nclass Foo\n{\n public function bar() {}\n}",
],
[
"<?php\nclass Foo\n{\r\n\r\n public function bar() {}\r\n\r\n}",
"<?php\nclass Foo\n{\r\n\r\n\n\n public function bar() {}\n\n\n\n}",
],
public function provideMessyWhitespacesCases(): iterable {
yield [
"<?php\nclass Foo\n{\r\n\r\n public function bar() {}\r\n\r\n}",
"<?php\nclass Foo\n{\n public function bar() {}\n}",
];
yield [
"<?php\nclass Foo\n{\r\n\r\n public function bar() {}\r\n\r\n}",
"<?php\nclass Foo\n{\r\n\r\n\n\n public function bar() {}\n\n\n\n}",
];
}
protected function createFixer() {
protected function createFixer(): AbstractFixer {
return new BlankLineAroundClassBodyFixer();
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Ely\CS\Test\Fixer\Whitespace;
use Ely\CS\Fixer\Whitespace\BlankLineBeforeReturnFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
use PhpCsFixer\WhitespacesFixerConfig;
@ -24,23 +25,19 @@ use PhpCsFixer\WhitespacesFixerConfig;
final class BlankLineBeforeReturnFixerTest extends AbstractFixerTestCase {
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideFixCases
*/
public function testFix($expected, $input = null) {
public function testFix(string $expected, ?string $input = null): void {
$this->doTest($expected, $input);
}
public function provideFixCases() {
$cases = [];
$cases[] = [
'$a = $a;
public function provideFixCases(): iterable {
yield [
'$a = $a;
return $a;
',
];
$cases[] = [
yield [
'<?php
$a = $a;
@ -48,7 +45,7 @@ return $a;',
'<?php
$a = $a; return $a;',
];
$cases[] = [
yield [
'<?php
$b = $b;
@ -56,7 +53,7 @@ return $b;',
'<?php
$b = $b;return $b;',
];
$cases[] = [
yield [
'<?php
$c = $c;
@ -65,7 +62,7 @@ return $c;',
$c = $c;
return $c;',
];
$cases[] = [
yield [
'<?php
$d = $d;
@ -74,19 +71,19 @@ return $c;',
$d = $d;
return $d;',
];
$cases[] = [
yield [
'<?php
if (true) {
return 1;
}',
];
$cases[] = [
yield [
'<?php
if (true)
return 1;
',
];
$cases[] = [
yield [
'<?php
if (true) {
return 1;
@ -94,7 +91,7 @@ return $c;',
return 2;
}',
];
$cases[] = [
yield [
'<?php
if (true)
return 1;
@ -102,7 +99,7 @@ return $c;',
return 2;
',
];
$cases[] = [
yield [
'<?php
if (true) {
return 1;
@ -110,7 +107,7 @@ return $c;',
return 2;
}',
];
$cases[] = [
yield [
'<?php
if (true)
return 1;
@ -118,11 +115,11 @@ return $c;',
return 2;
',
];
$cases[] = [
yield [
'<?php
throw new Exception("return true;");',
];
$cases[] = [
yield [
'<?php
function foo()
{
@ -130,7 +127,7 @@ return $c;',
return "foo";
}',
];
$cases[] = [
yield [
'<?php
function foo()
{
@ -139,7 +136,7 @@ return $c;',
return "bar";
}',
];
$cases[] = [
yield [
'<?php
function foo()
{
@ -147,7 +144,7 @@ return $c;',
return "bar";
}',
];
$cases[] = [
yield [
'<?php
function foo() {
$a = "a";
@ -162,14 +159,14 @@ return $c;',
return $a . $b;
}',
];
$cases[] = [
yield [
'<?php
function foo() {
$b = "b";
return $a . $b;
}',
];
$cases[] = [
yield [
'<?php
function foo() {
$a = "a";
@ -183,40 +180,33 @@ return $c;',
}
',
];
return $cases;
}
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideMessyWhitespacesCases
*/
public function testMessyWhitespaces($expected, $input = null) {
public function testMessyWhitespaces(string $expected, ?string $input = null): void {
$this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
$this->doTest($expected, $input);
}
public function provideMessyWhitespacesCases() {
return [
[
"<?php\r\n\$a = \$a;\r\n\r\nreturn \$a;",
"<?php\r\n\$a = \$a; return \$a;",
],
[
"<?php\r\n\$b = \$b;\r\n\r\nreturn \$b;",
"<?php\r\n\$b = \$b;return \$b;",
],
[
"<?php\r\n\$c = \$c;\r\n\r\nreturn \$c;",
"<?php\r\n\$c = \$c;\r\nreturn \$c;",
],
public function provideMessyWhitespacesCases(): iterable {
yield [
"<?php\r\n\$a = \$a;\r\n\r\nreturn \$a;",
"<?php\r\n\$a = \$a; return \$a;",
];
yield [
"<?php\r\n\$b = \$b;\r\n\r\nreturn \$b;",
"<?php\r\n\$b = \$b;return \$b;",
];
yield [
"<?php\r\n\$c = \$c;\r\n\r\nreturn \$c;",
"<?php\r\n\$c = \$c;\r\nreturn \$c;",
];
}
protected function createFixer() {
protected function createFixer(): AbstractFixer {
return new BlankLineBeforeReturnFixer();
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Ely\CS\Test\Fixer\Whitespace;
use Ely\CS\Fixer\Whitespace\LineBreakAfterStatementsFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
/**
@ -14,20 +15,15 @@ use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
class LineBreakAfterStatementsFixerTest extends AbstractFixerTestCase {
/**
* @param string $expected
* @param string $input
*
* @dataProvider provideFixCases
*/
public function testFix(string $expected, $input = null) {
public function testFix(string $expected, ?string $input = null): void {
$this->doTest($expected, $input);
}
public function provideFixCases() {
$cases = [];
public function provideFixCases(): iterable {
// Simple cases
$cases[] = [
yield [
'<?php
class Foo
{
@ -52,7 +48,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -81,7 +78,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -106,7 +104,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -131,7 +130,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -156,7 +156,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -181,7 +182,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -216,8 +218,9 @@ class Foo
}
}',
];
// Extended cases
$cases[] = [
yield [
'<?php
class Foo
{
@ -250,7 +253,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -283,7 +287,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -310,7 +315,8 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
class Foo
{
@ -351,19 +357,227 @@ class Foo
}
}',
];
$cases[] = [
yield [
'<?php
$a = "prev statement";
foreach ($coordinates as $coordinate) {
[$x, $y] = explode(\',\', $coordinate);
$points = explode(",", $coordinate);
}
',
];
return $cases;
// Issue 5
yield [
'<?php
class Foo
{
public function foo()
{
if ("a" === "b")
$this->bar();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
if ("a" === "b")
$this->bar();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function foo()
{
if ("a" === "b")
$this->bar();
else
$this->baz();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
if ("a" === "b")
$this->bar();
else
$this->baz();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function foo()
{
for ($i = 0; $i < 3; $i++)
$this->bar();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
for ($i = 0; $i < 3; $i++)
$this->bar();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function foo()
{
foreach (["foo", "bar"] as $str)
$this->bar();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
foreach (["foo", "bar"] as $str)
$this->bar();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function foo()
{
while ($i < 10)
$this->bar();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
while ($i < 10)
$this->bar();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function foo()
{
do
$this->bar();
while ($i < 10);
$a = "next statement";
}
}',
'<?php
class Foo
{
public function foo()
{
do
$this->bar();
while ($i < 10);
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function bar()
{
if ("a" === "b")
$this->foo();
else if ("a" === "c")
$this->bar();
else if ("a" === "d")
$this->baz();
$a = "next statement";
}
}',
'<?php
class Foo
{
public function bar()
{
if ("a" === "b")
$this->foo();
else if ("a" === "c")
$this->bar();
else if ("a" === "d")
$this->baz();
$a = "next statement";
}
}',
];
yield [
'<?php
class Foo
{
public function bar()
{
foreach (["foo", "bar"] as $str)
if ($str === "foo")
$this->bar();
return 3;
}
}',
'<?php
class Foo
{
public function bar()
{
foreach (["foo", "bar"] as $str)
if ($str === "foo")
$this->bar();
return 3;
}
}',
];
}
protected function createFixer() {
protected function createFixer(): AbstractFixer {
return new LineBreakAfterStatementsFixer();
}