diff --git a/.php_cs.fixture b/.php_cs.fixture index f15413d5..2a943d92 100644 --- a/.php_cs.fixture +++ b/.php_cs.fixture @@ -5,7 +5,9 @@ declare(strict_types=1); use Localheinz\PhpCsFixer\Config; $config = Config\Factory::fromRuleSet(new Config\RuleSet\Php71(''), [ + 'declare_strict_types' => false, 'final_class' => false, + 'header_comment' => false, 'lowercase_constants' => false, 'lowercase_keywords' => false, 'magic_method_casing' => false, diff --git a/.travis.yml b/.travis.yml index 41837a5a..6d2347cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -154,7 +154,7 @@ jobs: - mkdir -p $HOME/.build/infection script: - - vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=86 --min-msi=86 + - vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=98 --min-msi=85 notifications: email: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e193fa8..9bdb0f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), For a full diff see [`0.10.0...master`](https://github.com/localheinz/phpstan-rules/compare/0.10.0...master). +### Added + +* Added `Files\DeclareStrictTypesRule`, which reports an error when a PHP file does not have a `declare(strict_types=1)` declaration ([#79](https://github.com/localheinz/phpstan-rules/pull/79)), by [@dmecke](https://github.com/dmecke) + ### Changed * Require at least `nikic/php-parser:~0.11.15` ([#102](https://github.com/localheinz/phpstan-rules/pull/102)), by [@localheinz](https://github.com/localheinz) diff --git a/Makefile b/Makefile index 6b900fa2..f2c0126f 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ help: ## Displays this list of targets with descriptions infection: vendor ## Runs mutation tests with infection mkdir -p .build/infection - vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=86 --min-msi=86 + vendor/bin/infection --ignore-msi-with-no-mutations --min-covered-msi=98 --min-msi=85 stan: vendor ## Runs a static analysis with phpstan mkdir -p .build/phpstan diff --git a/README.md b/README.md index e8940890..b0428be0 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ This package provides the following rules for use with [`phpstan/phpstan`](https * [`Localheinz\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule`](https://github.com/localheinz/phpstan-rules#closuresnoparameterwithnullabletypedeclarationrule) * [`Localheinz\PHPStan\Rules\Closures\NoParameterWithNullDefaultValueRule`](https://github.com/localheinz/phpstan-rules#closuresnoparameterwithnulldefaultvaluerule) * [`Localheinz\PHPStan\Rules\Expressions\NoIssetRule`](https://github.com/localheinz/phpstan-rules#expressionsnoissetrule) +* [`Localheinz\PHPStan\Rules\Files\DeclareStrictTypesRule`](https://github.com/localheinz/phpstan-rules#filesdeclarestricttypesrule) * [`Localheinz\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule`](https://github.com/localheinz/phpstan-rules#functionsnonullablereturntypedeclarationrule) * [`Localheinz\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclaration`](https://github.com/localheinz/phpstan-rules#functionsnoparameterwithnullabletypedeclarationrule) * [`Localheinz\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule`](https://github.com/localheinz/phpstan-rules#functionsnoparameterwithnulldefaultvaluerule) @@ -121,6 +122,12 @@ This rule reports an error when a closure has a parameter with `null` as default This rule reports an error when the language construct `isset()` is used. +### Files + +#### `Files\DeclareStrictTypesRule` + +This rule reports an error when a non-empty file does not contain a `declare(strict_types=1)` declaration. + ### Functions #### `Functions\NoNullableReturnTypeDeclarationRule` diff --git a/rules.neon b/rules.neon index e7f1ebc3..8daedda9 100644 --- a/rules.neon +++ b/rules.neon @@ -12,6 +12,7 @@ rules: - Localheinz\PHPStan\Rules\Closures\NoNullableReturnTypeDeclarationRule - Localheinz\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule - Localheinz\PHPStan\Rules\Expressions\NoIssetRule + - Localheinz\PHPStan\Rules\Files\DeclareStrictTypesRule - Localheinz\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule - Localheinz\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclarationRule - Localheinz\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule diff --git a/src/Files/DeclareStrictTypesRule.php b/src/Files/DeclareStrictTypesRule.php new file mode 100644 index 00000000..a15758c9 --- /dev/null +++ b/src/Files/DeclareStrictTypesRule.php @@ -0,0 +1,63 @@ +getNodes(); + + if (0 === \count($nodes)) { + return []; + } + + $firstNode = \array_shift($nodes); + + if ($firstNode instanceof Node\Stmt\Declare_) { + foreach ($firstNode->declares as $declare) { + if ( + 'strict_types' === $declare->key->toLowerString() + && $declare->value instanceof Node\Scalar\LNumber + && 1 === $declare->value->value + ) { + return []; + } + } + } + + return [ + 'File is missing a "declare(strict_types=1)" declaration.', + ]; + } +} diff --git a/test/Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off-and-invalid-casing.php b/test/Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off-and-invalid-casing.php new file mode 100644 index 00000000..08650efe --- /dev/null +++ b/test/Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off-and-invalid-casing.php @@ -0,0 +1,7 @@ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-empty.php', + 'file-with-comment-and-declare-strict-types-on' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-comment-and-declare-strict-types-on.php', + 'file-with-comment-and-declare-strict-types-on-and-invalid-casing' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-comment-and-declare-strict-types-on-and-invalid-casing.php', + 'file-with-comment-and-declare-strict-types-on-and-multiple-declares' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-comment-and-declare-strict-types-on-and-multiple-declares.php', + 'file-with-comment-and-declare-strict-types-on-and-namespace-declaration' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-comment-and-declare-strict-types-on-and-namespace-declaration.php', + 'file-with-declare-strict-types-on' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-declare-strict-types-on.php', + 'file-with-declare-strict-types-on-and-invalid-casing' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-declare-strict-types-on-and-invalid-casing.php', + 'file-with-declare-strict-types-on-and-multiple-declares' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-declare-strict-types-on-and-multiple-declares.php', + 'file-with-declare-strict-types-on-and-namespace-declaration' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-declare-strict-types-on-and-namespace-declaration.php', + 'file-with-doc-block-and-declare-strict-types-on' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-doc-block-and-declare-strict-types-on.php', + 'file-with-doc-block-and-declare-strict-types-on-and-invalid-casing' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-doc-block-and-declare-strict-types-on-and-invalid-casing.php', + 'file-with-doc-block-and-declare-strict-types-on-and-multiple-declares' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-doc-block-and-declare-strict-types-on-and-multiple-declares.php', + 'file-with-doc-block-and-declare-strict-types-on-and-namespace-declaration' => __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Success/file-with-doc-block-and-declare-strict-types-on-and-namespace-declaration.php', + ]; + + foreach ($paths as $description => $path) { + yield $description => [ + $path, + ]; + } + } + + public function providerAnalysisFails(): iterable + { + $paths = [ + 'file-with-comment-and-declare-strict-types-off' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 5, + ], + ], + 'file-with-comment-and-declare-strict-types-off-and-invalid-casing' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off-and-invalid-casing.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 5, + ], + ], + 'file-with-comment-and-declare-strict-types-off-and-multiple-declares' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-comment-and-declare-strict-types-off-and-multiple-declares.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 5, + ], + ], + 'file-with-declare-strict-types-off' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-declare-strict-types-off.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + 'file-with-declare-strict-types-off-and-invalid-casing' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-declare-strict-types-off-and-invalid-casing.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + 'file-with-declare-strict-types-off-and-multiple-declares' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-declare-strict-types-off-and-multiple-declares.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + 'file-with-declare-ticks' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-declare-ticks.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + 'file-with-doc-block-and-declare-strict-types-off' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-doc-block-and-declare-strict-types-off.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 7, + ], + ], + 'file-with-doc-block-and-declare-strict-types-off-and-invalid-casing' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-doc-block-and-declare-strict-types-off-and-invalid-casing.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 7, + ], + ], + 'file-with-doc-block-and-declare-strict-types-off-and-multiple-declares' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-with-doc-block-and-declare-strict-types-off-and-multiple-declares.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 7, + ], + ], + 'file-without-declare-strict-types-and-namespace-declaration' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-without-declare-strict-types-and-namespace-declaration.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + 'file-without-declare-strict-types' => [ + __DIR__ . '/../../Fixture/Files/DeclareStrictTypesRule/Failure/file-without-declare-strict-types.php', + [ + 'File is missing a "declare(strict_types=1)" declaration.', + 3, + ], + ], + ]; + + foreach ($paths as $description => [$path, $error]) { + yield $description => [ + $path, + $error, + ]; + } + } + + protected function getRule(): Rule + { + return new DeclareStrictTypesRule(); + } +}