Repository: Roave/no-floaters
Branch: 1.16.x
Commit: f29123d0fb07
Files: 41
Total size: 40.2 KB
Directory structure:
gitextract_9qceq59d/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── continuous-integration.yml
│ └── release-on-milestone-closed.yml
├── .gitignore
├── .laminas-ci.json
├── LICENSE
├── README.md
├── SECURITY.md
├── composer-require-checker.json
├── composer.json
├── infection.json.dist
├── logo/
│ └── roave-no-floaters.blend
├── phpcs.xml.dist
├── phpstan.neon.dist
├── phpunit.xml.dist
├── psalm.xml
├── renovate.json
├── rules.neon
├── src/
│ ├── DisallowFloatAssignedToVariableRule.php
│ ├── DisallowFloatEverywhereRule.php
│ ├── DisallowFloatInFunctionSignatureRule.php
│ ├── DisallowFloatInMethodSignatureRule.php
│ ├── DisallowFloatPropertyTypeRule.php
│ └── FloatTypeHelper.php
└── tests/
├── asset/
│ ├── assign.php
│ ├── expr.php
│ ├── function.php
│ ├── functionNotAutoloaded.php
│ ├── functionWithInterpolatedFloatAndNonFloatParameters.php
│ ├── functionWithoutNamespace.php
│ ├── method.php
│ ├── methodWithConditionalReturnType.php
│ ├── methodWithInterpolatedFloatAndNotFloatParameters.php
│ └── property.php
└── src/
├── DisallowFloatAssignedToVariableRuleTest.php
├── DisallowFloatEverywhereRuleTest.php
├── DisallowFloatInFunctionSignatureRuleTest.php
├── DisallowFloatInMethodSignatureRuleTest.php
├── DisallowFloatPropertyTypeRuleTest.php
└── ScopeWithNodeCallbackInvoker.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
logo export-ignore
tests export-ignore
.gitignore export-ignore
.gitattributes export-ignore
.travis.yml export-ignore
composer-require-checker.json export-ignore
export-ignore export-ignore
phpcs.xml.dist export-ignore
phpstan.neon.dist export-ignore
phpunit.xml.dist export-ignore
================================================
FILE: .github/FUNDING.yml
================================================
tidelift: "packagist/roave/no-floaters"
================================================
FILE: .github/workflows/continuous-integration.yml
================================================
# See https://github.com/laminas/laminas-continuous-integration-action
# Generates a job matrix based on current dependencies and supported version
# ranges, then runs all those jobs
name: "Continuous Integration"
on:
pull_request:
push:
jobs:
matrix:
name: Generate job matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- name: Gather CI configuration
id: matrix
uses: laminas/laminas-ci-matrix-action@1.33.0
qa:
name: QA Checks
needs: [ matrix ]
runs-on: ${{ matrix.operatingSystem }}
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.matrix.outputs.matrix) }}
steps:
- name: ${{ matrix.name }}
uses: laminas/laminas-continuous-integration-action@1.43.0
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"INFECTION_DASHBOARD_API_KEY": ${{ secrets.INFECTION_DASHBOARD_API_KEY }}
"STRYKER_DASHBOARD_API_KEY": ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
with:
job: ${{ matrix.job }}
================================================
FILE: .github/workflows/release-on-milestone-closed.yml
================================================
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
name: "Automatic Releases"
on:
milestone:
types:
- "closed"
jobs:
release:
name: "GIT tag, release & create merge-up PR"
runs-on: ubuntu-latest
steps:
- name: "Checkout"
uses: "actions/checkout@v6"
- name: "Release"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:release"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create Merge-Up Pull Request"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create and/or Switch to new Release Branch"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor"
env:
"GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Bump Changelog Version On Originating Release Branch"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:bump-changelog"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create new milestones"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-milestones"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
================================================
FILE: .gitignore
================================================
/vendor
.phpunit.cache
.phpunit.result.cache
================================================
FILE: .laminas-ci.json
================================================
{
"extensions": [
"pcov"
],
"exclude": [
{"name": "Infection"}
],
"additional_checks": [
{
"name": "Infection (PCOV)",
"job": {
"php": "@lowest",
"dependencies": "locked",
"command": "./vendor/bin/roave-infection-static-analysis-plugin"
}
}
]
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) Roave, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# roave/no-floaters

[](https://packagist.org/packages/roave/no-floaters)
This library is a [PHPStan](https://github.com/phpstan/phpstan) plugin
that disallows:
* declaration of `float` properties
* `float` method parameters
* `float` method return types
* assignment of `float` values to variables or properties
The reason for this restriction is that rounding errors coming
from floating point arithmetic operations are not acceptable in
certain business logic scenario, such as dealing with money,
evaluating exam results, rocket science, etc.
An example of such problems can be seen with the following typical
[example](https://3v4l.org/MJqJe):
```php
var_dump((0.7 + 0.1) === 0.8); // output: bool(false)
```
This can mean no trouble at all, or a lot of trouble, depending
on how many numbers you are running through your system, so it
is advisable to avoid `float` for domains where rounding can
potentially lead to trouble.
`float` is still perfectly acceptable in many programming contexts,
and this ruleset should only be applied where it is critical not
to introduce rounding errors.
## Installation
```sh
composer require --dev roave/no-floaters
```
## Configuration
In your `phpstan.neon` configuration, add following section:
```neon
includes:
- vendor/roave/no-floaters/rules.neon
```
Optionally, you can configure the library to disallow any
`float`-producing expression at all, by adding following to your
`phpstan.neon`:
```neon
parameters:
disallowFloatsEverywhere: true
```
If the above is enabled, given the following `example-file.php`
contents:
```php
<?php
$a = 1 / 3;
```
You should get something like following:
```cli
vendor/bin/phpstan analyse example-file.php -l 7
1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
------ -----------------------------------------------------
Line example-file.php
------ -----------------------------------------------------
3 Cannot assign float to $a - floats are not allowed.
------ -----------------------------------------------------
[ERROR] Found 1 error
```
## roave/no-floaters for enterprise
Available as part of the Tidelift Subscription.
The maintainers of roave/no-floaters and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-roave-no-floaters?utm_source=packagist-roave-no-floaters&utm_medium=referral&utm_campaign=enterprise&utm_term=repo).
If you need help with setting up this library in your project,
you can contact us at <team@roave.com> for consulting/support.
================================================
FILE: SECURITY.md
================================================
## Security contact information
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
================================================
FILE: composer-require-checker.json
================================================
{
"symbol-whitelist": [
"null",
"true",
"false",
"static",
"self",
"parent",
"array",
"string",
"int",
"float",
"bool",
"iterable",
"callable",
"void",
"object",
"PHPStan\\Analyser\\Scope",
"PHPStan\\Node\\Printer\\Printer",
"PHPStan\\Reflection\\FunctionReflection",
"PHPStan\\Reflection\\MethodReflection",
"PHPStan\\Reflection\\ParametersAcceptor",
"PHPStan\\Reflection\\ReflectionProvider",
"PHPStan\\Rules\\Rule",
"PHPStan\\Rules\\RuleErrorBuilder",
"PHPStan\\ShouldNotHappenException",
"PHPStan\\Type\\FloatType",
"PHPStan\\Type\\LateResolvableType",
"PHPStan\\Type\\MixedType",
"PHPStan\\Type\\NeverType",
"PHPStan\\Type\\Type",
"PHPStan\\Type\\VerbosityLevel"
],
"php-core-extensions": [
"Core",
"date",
"pcre",
"Reflection",
"SPL",
"standard",
"mbstring"
]
}
================================================
FILE: composer.json
================================================
{
"name": "roave/no-floaters",
"type": "phpstan-extension",
"description": "PHPStan Rules to Disallow Float proliferation in contexts where IEEE-754 rounding errors are not acceptable",
"license": [
"MIT"
],
"require": {
"php": "~8.3.0 || ~8.4.0 || ~8.5.0",
"nikic/php-parser": "^5.7.0",
"phpstan/phpstan": "^2.1.39"
},
"require-dev": {
"doctrine/coding-standard": "^14.0.0",
"maglnet/composer-require-checker": "^4.20.0",
"phpstan/phpstan-phpunit": "^2.0.16",
"phpstan/phpstan-strict-rules": "^2.0.10",
"phpunit/phpunit": "^12.5.11",
"psalm/plugin-phpunit": "^0.19.5",
"roave/infection-static-analysis-plugin": "^1.43.0",
"squizlabs/php_codesniffer": "^4.0.1",
"vimeo/psalm": "^6.15.1"
},
"autoload": {
"psr-4": {
"Roave\\PHPStan\\Rules\\Floats\\": "src/"
}
},
"autoload-dev": {
"classmap": [
"tests/asset"
],
"psr-4": {
"Roave\\PHPStanTest\\Rules\\Floats\\": "tests/src"
}
},
"config": {
"allow-plugins": {
"infection/extension-installer": false,
"dealerdirect/phpcodesniffer-composer-installer": true
},
"platform": {
"php": "8.3.99"
},
"sort-packages": true
}
}
================================================
FILE: infection.json.dist
================================================
{
"$schema": "vendor/infection/infection/resources/schema.json",
"source": {
"directories": [
"src"
]
},
"logs": {
"text": "php://stderr",
"github": true
},
"mutators": {
"@default": true
},
"minMsi": 100,
"minCoveredMsi": 100
}
================================================
FILE: phpcs.xml.dist
================================================
<?xml version="1.0"?>
<ruleset
name="PHPStan Disallow Float Rules"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd"
>
<rule ref="Doctrine">
<exclude name="Generic.Files.LineLength.TooLong"/>
</rule>
<file>src</file>
<file>tests/src</file>
</ruleset>
================================================
FILE: phpstan.neon.dist
================================================
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
- rules.neon
parameters:
paths:
- %currentWorkingDirectory%/src
- %currentWorkingDirectory%/tests/src
level: 8
================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
failOnAllIssues="true"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutCoverageMetadata="true"
cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="PHPStan Disallow Float Test Suite">
<directory>./tests/src</directory>
</testsuite>
</testsuites>
<coverage ignoreDeprecatedCodeUnits="true" disableCodeCoverageIgnore="true"/>
<source>
<include>
<directory suffix=".php">src</directory>
</include>
</source>
</phpunit>
================================================
FILE: psalm.xml
================================================
<?xml version="1.0"?>
<psalm
errorLevel="1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<plugins>
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
</plugins>
<projectFiles>
<directory name="src" />
<directory name="tests" />
<ignoreFiles>
<directory name="vendor" />
<directory name="tests/asset" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<MissingOverrideAttribute errorLevel="suppress">
<!-- the #[Override] attribute is mostly useless -->
</MissingOverrideAttribute>
<PossiblyUnusedReturnValue>
<errorLevel type="suppress">
<!-- these files are visitors, and their return values are only used by the\
visitor implementation in PHPStan itself -->
<file name="src/DisallowFloatInMethodSignatureRule.php"/>
<file name="src/DisallowFloatPropertyTypeRule.php"/>
</errorLevel>
</PossiblyUnusedReturnValue>
</issueHandlers>
</psalm>
================================================
FILE: renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>Ocramius/.github:renovate-config"
]
}
================================================
FILE: rules.neon
================================================
rules:
- Roave\PHPStan\Rules\Floats\DisallowFloatAssignedToVariableRule
- Roave\PHPStan\Rules\Floats\DisallowFloatInFunctionSignatureRule
- Roave\PHPStan\Rules\Floats\DisallowFloatInMethodSignatureRule
- Roave\PHPStan\Rules\Floats\DisallowFloatPropertyTypeRule
parameters:
disallowFloatsEverywhere: false
conditionalTags:
Roave\PHPStan\Rules\Floats\DisallowFloatEverywhereRule:
phpstan.rules.rule: %disallowFloatsEverywhere%
services:
-
class: Roave\PHPStan\Rules\Floats\DisallowFloatEverywhereRule
parametersSchema:
disallowFloatsEverywhere: bool()
================================================
FILE: src/DisallowFloatAssignedToVariableRule.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\Printer\Printer;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/** @implements Rule<Node> */
final class DisallowFloatAssignedToVariableRule implements Rule
{
public function __construct(private Printer $printer)
{
}
public function getNodeType(): string
{
return Node::class;
}
/**
* {@inheritDoc}
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $node instanceof Node\Expr\AssignOp && ! $node instanceof Node\Expr\Assign) {
return [];
}
$resultType = $scope->getType($node);
if (! FloatTypeHelper::isFloat($resultType)) {
return [];
}
return [
RuleErrorBuilder::message(sprintf(
'Cannot assign %s to %s - floats are not allowed.',
$resultType->describe(VerbosityLevel::typeOnly()),
$this->printer->prettyPrintExpr($node->var),
))->identifier('float.assign')->build(),
];
}
}
================================================
FILE: src/DisallowFloatEverywhereRule.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/**
* @implements Rule<Expr>
* @final not designed for inheritance, but kept open for BC, until the next major release
*/
class DisallowFloatEverywhereRule implements Rule
{
public function getNodeType(): string
{
return Expr::class;
}
/**
* {@inheritDoc}
*/
public function processNode(Node $node, Scope $scope): array
{
if (
$node instanceof Node\Expr\AssignOp
|| $node instanceof Node\Expr\Assign
) {
return [];
}
$nodeType = $scope->getType($node);
if (! FloatTypeHelper::isFloat($nodeType)) {
return [];
}
return [
RuleErrorBuilder::message(sprintf(
'Cannot have %s as a result type of this expression - floats are not allowed.',
$nodeType->describe(VerbosityLevel::typeOnly()),
))->identifier('float.expression')->build(),
];
}
}
================================================
FILE: src/DisallowFloatInFunctionSignatureRule.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Function_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function array_filter;
use function array_keys;
use function array_map;
use function array_merge;
use function array_values;
use function sprintf;
/** @implements Rule<Function_> */
final class DisallowFloatInFunctionSignatureRule implements Rule
{
public function __construct(private ReflectionProvider $reflectionProvider)
{
}
public function getNodeType(): string
{
return Function_::class;
}
/**
* {@inheritDoc}
*/
public function processNode(Node $node, Scope $scope): array
{
$functionName = new Name($node->name->toString());
if (! $this->reflectionProvider->hasFunction($functionName, $scope)) {
return [];
}
$functionReflection = $this->reflectionProvider->getFunction($functionName, $scope);
$errors = [];
foreach ($functionReflection->getVariants() as $functionVariant) {
$errors[] = $this->violationsForParameters($functionVariant, $functionReflection);
$errors[] = $this->returnTypeViolations($functionVariant, $functionReflection);
}
return array_merge([], ...$errors);
}
/** @return list<IdentifierRuleError> */
private function returnTypeViolations(
ParametersAcceptor $function,
FunctionReflection $functionReflection,
): array {
if (! FloatTypeHelper::isFloat($function->getReturnType())) {
return [];
}
return [
RuleErrorBuilder::message(sprintf(
'Function %s() cannot have %s as its return type - floats are not allowed.',
$functionReflection->getName(),
$function->getReturnType()->describe(VerbosityLevel::typeOnly()),
))->identifier('float.function')->build(),
];
}
/** @return list<IdentifierRuleError> */
private function violationsForParameters(
ParametersAcceptor $function,
FunctionReflection $functionReflection,
): array {
$parameters = $function->getParameters();
return array_values(array_filter(array_map(
static function (ParameterReflection $parameter, int $index) use ($functionReflection): RuleError|null {
if (! FloatTypeHelper::isFloat($parameter->getType())) {
return null;
}
return RuleErrorBuilder::message(sprintf(
'Parameter #%d $%s of function %s() cannot have %s as its type - floats are not allowed.',
$index + 1,
$parameter->getName(),
$functionReflection->getName(),
$parameter->getType()->describe(VerbosityLevel::typeOnly()),
))->identifier('float.function')->build();
},
$parameters,
array_keys($parameters),
), static fn (RuleError|null $error): bool => $error !== null));
}
}
================================================
FILE: src/DisallowFloatInMethodSignatureRule.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\VerbosityLevel;
use function array_filter;
use function array_keys;
use function array_map;
use function array_merge;
use function array_values;
use function sprintf;
/** @implements Rule<ClassMethod> */
final class DisallowFloatInMethodSignatureRule implements Rule
{
public function getNodeType(): string
{
return ClassMethod::class;
}
/**
* {@inheritDoc}
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $scope->isInClass()) {
throw new ShouldNotHappenException();
}
/** @psalm-var ClassReflection $classReflection */
$classReflection = $scope->getClassReflection();
$methodName = $node->name->toString();
$method = $classReflection->getNativeMethod($methodName);
$errors = [];
foreach ($method->getVariants() as $methodVariant) {
$errors[] = $this->violationsForParameters($methodVariant, $method);
$errors[] = $this->returnTypeViolations($methodVariant, $method);
}
return array_merge([], ...$errors);
}
/** @return list<IdentifierRuleError> */
private function returnTypeViolations(
ParametersAcceptor $method,
MethodReflection $methodReflection,
): array {
if (! FloatTypeHelper::isFloat($method->getReturnType())) {
return [];
}
return [
RuleErrorBuilder::message(sprintf(
'Method %s::%s() cannot have %s as its return type - floats are not allowed.',
$methodReflection->getDeclaringClass()->getDisplayName(),
$methodReflection->getName(),
$method->getReturnType()->describe(VerbosityLevel::typeOnly()),
))->identifier('float.type')->build(),
];
}
/** @return list<IdentifierRuleError> */
private function violationsForParameters(
ParametersAcceptor $function,
MethodReflection $methodReflection,
): array {
$parameters = $function->getParameters();
return array_values(array_filter(array_map(
static function (ParameterReflection $parameter, int $index) use ($methodReflection): RuleError|null {
if (! FloatTypeHelper::isFloat($parameter->getType())) {
return null;
}
return RuleErrorBuilder::message(sprintf(
'Parameter #%d $%s of method %s::%s() cannot have %s as its type - floats are not allowed.',
$index + 1,
$parameter->getName(),
$methodReflection->getDeclaringClass()->getDisplayName(),
$methodReflection->getName(),
$parameter->getType()->describe(VerbosityLevel::typeOnly()),
))->identifier('float.type')->build();
},
$parameters,
array_keys($parameters),
), static fn (RuleError|null $error): bool => $error !== null));
}
}
================================================
FILE: src/DisallowFloatPropertyTypeRule.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PhpParser\Node;
use PhpParser\Node\PropertyItem;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/** @implements Rule<PropertyItem> */
final class DisallowFloatPropertyTypeRule implements Rule
{
public function getNodeType(): string
{
return PropertyItem::class;
}
/**
* {@inheritDoc}
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $scope->isInClass()) {
throw new ShouldNotHappenException();
}
/** @psalm-var ClassReflection $classReflection */
$classReflection = $scope->getClassReflection();
$propertyName = $node->name->toString();
$property = $classReflection->getNativeProperty($node->name->toString());
$propertyType = $property->getReadableType();
if (! FloatTypeHelper::isFloat($propertyType)) {
return [];
}
return [
RuleErrorBuilder::message(sprintf(
'Property %s::$%s cannot have %s as its type - floats are not allowed.',
$property->getDeclaringClass()->getDisplayName(),
$propertyName,
$propertyType->describe(VerbosityLevel::typeOnly()),
))->identifier('float.property')->build(),
];
}
}
================================================
FILE: src/FloatTypeHelper.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStan\Rules\Floats;
use PHPStan\Type\FloatType;
use PHPStan\Type\LateResolvableType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\Type;
/** @internal class is only for internal tooling use: do not import it in your own projects */
final class FloatTypeHelper
{
public static function isFloat(Type $type): bool
{
if ($type instanceof MixedType) {
return false;
}
if ($type instanceof NeverType) {
return false;
}
if ($type instanceof LateResolvableType) {
return self::isFloat($type->resolve());
}
return ! (new FloatType())->isSuperTypeOf($type)->no();
}
}
================================================
FILE: tests/asset/assign.php
================================================
<?php
namespace DisallowFloatsInAssign;
class Foo
{
private $foo;
private $bar;
/**
* @param float $float
* @param int|float $intOrFloat
*/
public function doFoo($float, $intOrFloat, string $str)
{
$test = $float;
$test2 = $intOrFloat;
$this->foo = $float;
$this->bar['test'] = $float;
$test3 = $str;
}
public function doBar()
{
$test = 0;
$test += 1;
$test += 3.14;
}
}
================================================
FILE: tests/asset/expr.php
================================================
<?php
namespace DisallowFloatsEverywhere;
function () {
$foo = 1.3;
$foo += 1.3;
foo(
3.14
);
};
================================================
FILE: tests/asset/function.php
================================================
<?php
namespace DisallowFloatsInFunctionSignatures;
/**
* @param float $float
* @param int|float $intOrFloat
* @param string $string
* @return float
*/
function doFoo(
float $float,
$intOrFloat,
string $string,
$mixed
): float
{
}
function doBar(): string
{
}
/**
* @return never
*/
function withNever()
{
throw new \RuntimeException();
}
================================================
FILE: tests/asset/functionNotAutoloaded.php
================================================
<?php
function nonexistentRoaveFunction(): float
{
}
================================================
FILE: tests/asset/functionWithInterpolatedFloatAndNonFloatParameters.php
================================================
<?php
namespace DisallowFloatsInFunctionSignatures;
/** @param mixed $d */
function functionWithInterpolatedFloatAndNonFloatParameters(
float $a,
string $b,
float $c,
$d,
float $e
) {
}
================================================
FILE: tests/asset/functionWithoutNamespace.php
================================================
<?php
/**
* @param float $float
* @param int|float $intOrFloat
* @param string $string
* @return float
*/
function doFoo(
float $float,
$intOrFloat,
string $string,
$mixed
): float
{
}
function doBar(): string
{
}
================================================
FILE: tests/asset/method.php
================================================
<?php
namespace DisallowFloatsInMethodSignatures;
class Foo
{
/**
* @param float $float
* @param int|float $intOrFloat
* @param string $string
* @return float
*/
public function doFoo(
float $float,
$intOrFloat,
string $string,
$mixed
): float
{
}
public function doBar(): string
{
}
/**
* @return never
*/
public function withNever()
{
throw new \RuntimeException();
}
}
================================================
FILE: tests/asset/methodWithConditionalReturnType.php
================================================
<?php
namespace DisallowFloatsInMethodSignatures;
use Exception;
use function gettype;
/**
* @template TObject of object
*/
interface DenormalizerInterface
{
/**
* @param class-string<TObject>|string $type
* @return ($type is class-string<TObject> ? TObject : mixed)
*/
public function denormalize(mixed $data, string $type): mixed;
}
class Denormalizer implements DenormalizerInterface
{
public function denormalize(mixed $data, string $type): mixed
{
return new \stdClass();
}
}
class DummyTypeConverter {
/**
* @template RequestedType of 'float'|'int'
* @param RequestedType $type
* @return (RequestedType is 'float' ? float : int)
*/
function convertToNumber(mixed $input, string $type): mixed {
throw new Exception('irrelevant - ' . gettype($input) . ' - ' . $type);
}
/**
* @template RequestedType of 'float'|'int'
* @param RequestedType $type
* @return (RequestedType is 'int' ? int : float)
*/
function convertToNumber2(mixed $input, string $type): mixed {
throw new Exception('irrelevant - ' . gettype($input) . ' - ' . $type);
}
}
================================================
FILE: tests/asset/methodWithInterpolatedFloatAndNotFloatParameters.php
================================================
<?php
namespace DisallowFloatsInMethodSignatures;
class Bar
{
/** @param mixed $d */
public function doFoo(
float $a,
string $b,
float $c,
$d,
float $e
) {
}
}
================================================
FILE: tests/asset/property.php
================================================
<?php
namespace DisallowFloatsInProperties;
class Foo
{
/** @var float */
private $foo;
/** @var float|int */
private $bar;
/** @var int */
private $baz;
/** @var mixed */
private $taz;
}
================================================
FILE: tests/src/DisallowFloatAssignedToVariableRuleTest.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PHPStan\Node\Printer\Printer;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Roave\PHPStan\Rules\Floats\DisallowFloatAssignedToVariableRule;
/** @extends RuleTestCase<DisallowFloatAssignedToVariableRule> */
final class DisallowFloatAssignedToVariableRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
/** @phpstan-ignore phpstanApi.constructor */
return new DisallowFloatAssignedToVariableRule(new Printer());
}
public function testRule(): void
{
$this->analyse([__DIR__ . '/../asset/assign.php'], [
[
'Cannot assign float to $test - floats are not allowed.',
18,
],
[
'Cannot assign float|int to $test2 - floats are not allowed.',
19,
],
[
'Cannot assign float to $this->foo - floats are not allowed.',
21,
],
[
'Cannot assign float to $this->bar[\'test\'] - floats are not allowed.',
22,
],
[
'Cannot assign float to $test - floats are not allowed.',
31,
],
]);
}
}
================================================
FILE: tests/src/DisallowFloatEverywhereRuleTest.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Roave\PHPStan\Rules\Floats\DisallowFloatEverywhereRule;
/** @extends RuleTestCase<DisallowFloatEverywhereRule> */
final class DisallowFloatEverywhereRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new DisallowFloatEverywhereRule();
}
public function testRule(): void
{
$this->analyse([__DIR__ . '/../asset/expr.php'], [
[
'Cannot have float as a result type of this expression - floats are not allowed.',
6,
],
[
'Cannot have float as a result type of this expression - floats are not allowed.',
7,
],
[
'Cannot have float as a result type of this expression - floats are not allowed.',
7,
],
[
'Cannot have float as a result type of this expression - floats are not allowed.',
10,
],
]);
}
}
================================================
FILE: tests/src/DisallowFloatInFunctionSignatureRuleTest.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Roave\PHPStan\Rules\Floats\DisallowFloatInFunctionSignatureRule;
/** @extends RuleTestCase<DisallowFloatInFunctionSignatureRule> */
final class DisallowFloatInFunctionSignatureRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new DisallowFloatInFunctionSignatureRule($this->createReflectionProvider());
}
public function testRule(): void
{
require_once __DIR__ . '/../asset/function.php';
$this->analyse([__DIR__ . '/../asset/function.php'], [
[
'Parameter #1 $float of function DisallowFloatsInFunctionSignatures\doFoo() cannot have float as its type - floats are not allowed.',
11,
],
[
'Parameter #2 $intOrFloat of function DisallowFloatsInFunctionSignatures\doFoo() cannot have float|int as its type - floats are not allowed.',
11,
],
[
'Function DisallowFloatsInFunctionSignatures\doFoo() cannot have float as its return type - floats are not allowed.',
11,
],
]);
}
public function testRuleWithoutNamespace(): void
{
require_once __DIR__ . '/../asset/functionWithoutNamespace.php';
$this->analyse([__DIR__ . '/../asset/functionWithoutNamespace.php'], [
[
'Parameter #1 $float of function doFoo() cannot have float as its type - floats are not allowed.',
9,
],
[
'Parameter #2 $intOrFloat of function doFoo() cannot have float|int as its type - floats are not allowed.',
9,
],
[
'Function doFoo() cannot have float as its return type - floats are not allowed.',
9,
],
]);
}
public function testRuleShowsAllFloatParametersAsViolations(): void
{
require_once __DIR__ . '/../asset/functionWithInterpolatedFloatAndNonFloatParameters.php';
$this->analyse([__DIR__ . '/../asset/functionWithInterpolatedFloatAndNonFloatParameters.php'], [
[
'Parameter #1 $a of function DisallowFloatsInFunctionSignatures\functionWithInterpolatedFloatAndNonFloatParameters() cannot have float as its type - floats are not allowed.',
6,
],
[
'Parameter #3 $c of function DisallowFloatsInFunctionSignatures\functionWithInterpolatedFloatAndNonFloatParameters() cannot have float as its type - floats are not allowed.',
6,
],
[
'Parameter #5 $e of function DisallowFloatsInFunctionSignatures\functionWithInterpolatedFloatAndNonFloatParameters() cannot have float as its type - floats are not allowed.',
6,
],
]);
}
public function testNotAutoloadedFunction(): void
{
$this->analyse(
[__DIR__ . '/../asset/functionNotAutoloaded.php'],
[
[
'Function nonexistentRoaveFunction() cannot have float as its return type - floats are not allowed.',
3,
],
],
);
}
}
================================================
FILE: tests/src/DisallowFloatInMethodSignatureRuleTest.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Rules\Rule;
use PHPStan\ShouldNotHappenException;
use PHPStan\Testing\RuleTestCase;
use Roave\PHPStan\Rules\Floats\DisallowFloatInMethodSignatureRule;
/** @extends RuleTestCase<DisallowFloatInMethodSignatureRule> */
final class DisallowFloatInMethodSignatureRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new DisallowFloatInMethodSignatureRule();
}
public function testRule(): void
{
$this->analyse([__DIR__ . '/../asset/method.php'], [
[
'Parameter #1 $float of method DisallowFloatsInMethodSignatures\Foo::doFoo() cannot have float as its type - floats are not allowed.',
14,
],
[
'Parameter #2 $intOrFloat of method DisallowFloatsInMethodSignatures\Foo::doFoo() cannot have float|int as its type - floats are not allowed.',
14,
],
[
'Method DisallowFloatsInMethodSignatures\Foo::doFoo() cannot have float as its return type - floats are not allowed.',
14,
],
]);
}
public function testRuleShowsAllFloatParametersAsViolations(): void
{
$this->analyse([__DIR__ . '/../asset/methodWithInterpolatedFloatAndNotFloatParameters.php'], [
[
'Parameter #1 $a of method DisallowFloatsInMethodSignatures\Bar::doFoo() cannot have float as its type - floats are not allowed.',
8,
],
[
'Parameter #3 $c of method DisallowFloatsInMethodSignatures\Bar::doFoo() cannot have float as its type - floats are not allowed.',
8,
],
[
'Parameter #5 $e of method DisallowFloatsInMethodSignatures\Bar::doFoo() cannot have float as its type - floats are not allowed.',
8,
],
]);
}
/**
* Verifies that conditional return types containing mixed are not flagged as floats.
*
* @see https://github.com/Roave/no-floaters/issues/126
*/
public function testRuleDoesNotFlagConditionalReturnTypesContainingMixed(): void
{
$this->analyse(
[__DIR__ . '/../asset/methodWithConditionalReturnType.php'],
[
[
'Method DisallowFloatsInMethodSignatures\DummyTypeConverter::convertToNumber() cannot have (RequestedType of string is string ? float : int) as its return type - floats are not allowed.',
35,
],
[
'Method DisallowFloatsInMethodSignatures\DummyTypeConverter::convertToNumber2() cannot have (RequestedType of string is string ? int : float) as its return type - floats are not allowed.',
44,
],
],
);
}
/**
* Verifies that the impossible scenario of a method signature is not declared in a class method
*/
public function testRuleWillNotWorkWhenNotInClassScope(): void
{
$rule = new DisallowFloatInMethodSignatureRule();
$node = self::createStub(ClassMethod::class);
$scope = self::createStub(ScopeWithNodeCallbackInvoker::class);
$scope
->method('isInClass')
->willReturn(false);
$this->expectException(ShouldNotHappenException::class);
$this->expectExceptionMessage('Internal error.');
$rule->processNode($node, $scope);
}
}
================================================
FILE: tests/src/DisallowFloatPropertyTypeRuleTest.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PhpParser\Node\PropertyItem;
use PHPStan\Rules\Rule;
use PHPStan\ShouldNotHappenException;
use PHPStan\Testing\RuleTestCase;
use Roave\PHPStan\Rules\Floats\DisallowFloatPropertyTypeRule;
/** @extends RuleTestCase<DisallowFloatPropertyTypeRule> */
final class DisallowFloatPropertyTypeRuleTest extends RuleTestCase
{
protected function getRule(): Rule
{
return new DisallowFloatPropertyTypeRule();
}
public function testRule(): void
{
$this->analyse([__DIR__ . '/../asset/property.php'], [
[
'Property DisallowFloatsInProperties\Foo::$foo cannot have float as its type - floats are not allowed.',
9,
],
[
'Property DisallowFloatsInProperties\Foo::$bar cannot have float|int as its type - floats are not allowed.',
12,
],
]);
}
/**
* Verifies that the impossible scenario of a method signature is not declared in a class method
*/
public function testRuleWillNotWorkWhenNotInClassScope(): void
{
$rule = new DisallowFloatPropertyTypeRule();
$node = self::createStub(PropertyItem::class);
$scope = self::createStub(ScopeWithNodeCallbackInvoker::class);
$scope
->method('isInClass')
->willReturn(false);
$this->expectException(ShouldNotHappenException::class);
$this->expectExceptionMessage('Internal error.');
$rule->processNode($node, $scope);
}
}
================================================
FILE: tests/src/ScopeWithNodeCallbackInvoker.php
================================================
<?php
declare(strict_types=1);
namespace Roave\PHPStanTest\Rules\Floats;
use PHPStan\Analyser\NodeCallbackInvoker;
use PHPStan\Analyser\Scope;
/** @phpstan-ignore phpstanApi.interface */
interface ScopeWithNodeCallbackInvoker extends Scope, NodeCallbackInvoker
{
}
gitextract_9qceq59d/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── continuous-integration.yml
│ └── release-on-milestone-closed.yml
├── .gitignore
├── .laminas-ci.json
├── LICENSE
├── README.md
├── SECURITY.md
├── composer-require-checker.json
├── composer.json
├── infection.json.dist
├── logo/
│ └── roave-no-floaters.blend
├── phpcs.xml.dist
├── phpstan.neon.dist
├── phpunit.xml.dist
├── psalm.xml
├── renovate.json
├── rules.neon
├── src/
│ ├── DisallowFloatAssignedToVariableRule.php
│ ├── DisallowFloatEverywhereRule.php
│ ├── DisallowFloatInFunctionSignatureRule.php
│ ├── DisallowFloatInMethodSignatureRule.php
│ ├── DisallowFloatPropertyTypeRule.php
│ └── FloatTypeHelper.php
└── tests/
├── asset/
│ ├── assign.php
│ ├── expr.php
│ ├── function.php
│ ├── functionNotAutoloaded.php
│ ├── functionWithInterpolatedFloatAndNonFloatParameters.php
│ ├── functionWithoutNamespace.php
│ ├── method.php
│ ├── methodWithConditionalReturnType.php
│ ├── methodWithInterpolatedFloatAndNotFloatParameters.php
│ └── property.php
└── src/
├── DisallowFloatAssignedToVariableRuleTest.php
├── DisallowFloatEverywhereRuleTest.php
├── DisallowFloatInFunctionSignatureRuleTest.php
├── DisallowFloatInMethodSignatureRuleTest.php
├── DisallowFloatPropertyTypeRuleTest.php
└── ScopeWithNodeCallbackInvoker.php
SYMBOL INDEX (70 symbols across 21 files)
FILE: src/DisallowFloatAssignedToVariableRule.php
class DisallowFloatAssignedToVariableRule (line 17) | final class DisallowFloatAssignedToVariableRule implements Rule
method __construct (line 19) | public function __construct(private Printer $printer)
method getNodeType (line 23) | public function getNodeType(): string
method processNode (line 31) | public function processNode(Node $node, Scope $scope): array
FILE: src/DisallowFloatEverywhereRule.php
class DisallowFloatEverywhereRule (line 20) | class DisallowFloatEverywhereRule implements Rule
method getNodeType (line 22) | public function getNodeType(): string
method processNode (line 30) | public function processNode(Node $node, Scope $scope): array
FILE: src/DisallowFloatInFunctionSignatureRule.php
class DisallowFloatInFunctionSignatureRule (line 29) | final class DisallowFloatInFunctionSignatureRule implements Rule
method __construct (line 31) | public function __construct(private ReflectionProvider $reflectionProv...
method getNodeType (line 35) | public function getNodeType(): string
method processNode (line 43) | public function processNode(Node $node, Scope $scope): array
method returnTypeViolations (line 63) | private function returnTypeViolations(
method violationsForParameters (line 81) | private function violationsForParameters(
FILE: src/DisallowFloatInMethodSignatureRule.php
class DisallowFloatInMethodSignatureRule (line 29) | final class DisallowFloatInMethodSignatureRule implements Rule
method getNodeType (line 31) | public function getNodeType(): string
method processNode (line 39) | public function processNode(Node $node, Scope $scope): array
method returnTypeViolations (line 61) | private function returnTypeViolations(
method violationsForParameters (line 80) | private function violationsForParameters(
FILE: src/DisallowFloatPropertyTypeRule.php
class DisallowFloatPropertyTypeRule (line 19) | final class DisallowFloatPropertyTypeRule implements Rule
method getNodeType (line 21) | public function getNodeType(): string
method processNode (line 29) | public function processNode(Node $node, Scope $scope): array
FILE: src/FloatTypeHelper.php
class FloatTypeHelper (line 14) | final class FloatTypeHelper
method isFloat (line 16) | public static function isFloat(Type $type): bool
FILE: tests/asset/assign.php
class Foo (line 5) | class Foo
method doFoo (line 16) | public function doFoo($float, $intOrFloat, string $str)
method doBar (line 27) | public function doBar()
FILE: tests/asset/function.php
function doFoo (line 11) | function doFoo(
function doBar (line 21) | function doBar(): string
function withNever (line 29) | function withNever()
FILE: tests/asset/functionNotAutoloaded.php
function nonexistentRoaveFunction (line 3) | function nonexistentRoaveFunction(): float
FILE: tests/asset/functionWithInterpolatedFloatAndNonFloatParameters.php
function functionWithInterpolatedFloatAndNonFloatParameters (line 6) | function functionWithInterpolatedFloatAndNonFloatParameters(
FILE: tests/asset/functionWithoutNamespace.php
function doFoo (line 9) | function doFoo(
function doBar (line 19) | function doBar(): string
FILE: tests/asset/method.php
class Foo (line 5) | class Foo
method doFoo (line 14) | public function doFoo(
method doBar (line 24) | public function doBar(): string
method withNever (line 32) | public function withNever()
FILE: tests/asset/methodWithConditionalReturnType.php
type DenormalizerInterface (line 12) | interface DenormalizerInterface
method denormalize (line 18) | public function denormalize(mixed $data, string $type): mixed;
class Denormalizer (line 21) | class Denormalizer implements DenormalizerInterface
method denormalize (line 23) | public function denormalize(mixed $data, string $type): mixed
class DummyTypeConverter (line 29) | class DummyTypeConverter {
method convertToNumber (line 35) | function convertToNumber(mixed $input, string $type): mixed {
method convertToNumber2 (line 44) | function convertToNumber2(mixed $input, string $type): mixed {
FILE: tests/asset/methodWithInterpolatedFloatAndNotFloatParameters.php
class Bar (line 5) | class Bar
method doFoo (line 8) | public function doFoo(
FILE: tests/asset/property.php
class Foo (line 5) | class Foo
FILE: tests/src/DisallowFloatAssignedToVariableRuleTest.php
class DisallowFloatAssignedToVariableRuleTest (line 13) | final class DisallowFloatAssignedToVariableRuleTest extends RuleTestCase
method getRule (line 15) | protected function getRule(): Rule
method testRule (line 21) | public function testRule(): void
FILE: tests/src/DisallowFloatEverywhereRuleTest.php
class DisallowFloatEverywhereRuleTest (line 12) | final class DisallowFloatEverywhereRuleTest extends RuleTestCase
method getRule (line 14) | protected function getRule(): Rule
method testRule (line 19) | public function testRule(): void
FILE: tests/src/DisallowFloatInFunctionSignatureRuleTest.php
class DisallowFloatInFunctionSignatureRuleTest (line 12) | final class DisallowFloatInFunctionSignatureRuleTest extends RuleTestCase
method getRule (line 14) | protected function getRule(): Rule
method testRule (line 19) | public function testRule(): void
method testRuleWithoutNamespace (line 38) | public function testRuleWithoutNamespace(): void
method testRuleShowsAllFloatParametersAsViolations (line 57) | public function testRuleShowsAllFloatParametersAsViolations(): void
method testNotAutoloadedFunction (line 76) | public function testNotAutoloadedFunction(): void
FILE: tests/src/DisallowFloatInMethodSignatureRuleTest.php
class DisallowFloatInMethodSignatureRuleTest (line 14) | final class DisallowFloatInMethodSignatureRuleTest extends RuleTestCase
method getRule (line 16) | protected function getRule(): Rule
method testRule (line 21) | public function testRule(): void
method testRuleShowsAllFloatParametersAsViolations (line 39) | public function testRuleShowsAllFloatParametersAsViolations(): void
method testRuleDoesNotFlagConditionalReturnTypesContainingMixed (line 62) | public function testRuleDoesNotFlagConditionalReturnTypesContainingMix...
method testRuleWillNotWorkWhenNotInClassScope (line 82) | public function testRuleWillNotWorkWhenNotInClassScope(): void
FILE: tests/src/DisallowFloatPropertyTypeRuleTest.php
class DisallowFloatPropertyTypeRuleTest (line 14) | final class DisallowFloatPropertyTypeRuleTest extends RuleTestCase
method getRule (line 16) | protected function getRule(): Rule
method testRule (line 21) | public function testRule(): void
method testRuleWillNotWorkWhenNotInClassScope (line 38) | public function testRuleWillNotWorkWhenNotInClassScope(): void
FILE: tests/src/ScopeWithNodeCallbackInvoker.php
type ScopeWithNodeCallbackInvoker (line 11) | interface ScopeWithNodeCallbackInvoker extends Scope, NodeCallbackInvoker
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (46K chars).
[
{
"path": ".gitattributes",
"chars": 283,
"preview": "logo export-ignore\ntests export-ignore\n.gitignore export-ignore\n.gitattributes export-ignore\n.travis.yml export-ignore\nc"
},
{
"path": ".github/FUNDING.yml",
"chars": 40,
"preview": "tidelift: \"packagist/roave/no-floaters\"\n"
},
{
"path": ".github/workflows/continuous-integration.yml",
"chars": 1078,
"preview": "# See https://github.com/laminas/laminas-continuous-integration-action\n# Generates a job matrix based on current depende"
},
{
"path": ".github/workflows/release-on-milestone-closed.yml",
"chars": 2525,
"preview": "# https://help.github.com/en/categories/automating-your-workflow-with-github-actions\n\nname: \"Automatic Releases\"\n\non:\n "
},
{
"path": ".gitignore",
"chars": 44,
"preview": "/vendor\n.phpunit.cache\n.phpunit.result.cache"
},
{
"path": ".laminas-ci.json",
"chars": 314,
"preview": "{\n \"extensions\": [\n \"pcov\"\n ],\n \"exclude\": [\n {\"name\": \"Infection\"}\n ],\n \"additional_checks\": [\n {\n \""
},
{
"path": "LICENSE",
"chars": 1062,
"preview": "MIT License\n\nCopyright (c) Roave, LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof t"
},
{
"path": "README.md",
"chars": 2912,
"preview": "# roave/no-floaters\n\n\n\n[;\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PhpParser\\Node;\nuse PHPStan\\Analyser\\Scope;\n"
},
{
"path": "src/DisallowFloatEverywhereRule.php",
"chars": 1218,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse"
},
{
"path": "src/DisallowFloatInFunctionSignatureRule.php",
"chars": 3455,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Name;\nuse"
},
{
"path": "src/DisallowFloatInMethodSignatureRule.php",
"chars": 3536,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt\\Clas"
},
{
"path": "src/DisallowFloatPropertyTypeRule.php",
"chars": 1541,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\PropertyI"
},
{
"path": "src/FloatTypeHelper.php",
"chars": 745,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStan\\Rules\\Floats;\n\nuse PHPStan\\Type\\FloatType;\nuse PHPStan\\Type\\Lat"
},
{
"path": "tests/asset/assign.php",
"chars": 495,
"preview": "<?php\n\nnamespace DisallowFloatsInAssign;\n\nclass Foo\n{\n\n private $foo;\n\n private $bar;\n\n /**\n * @param float"
},
{
"path": "tests/asset/expr.php",
"chars": 124,
"preview": "<?php\n\nnamespace DisallowFloatsEverywhere;\n\nfunction () {\n $foo = 1.3;\n $foo += 1.3;\n\n foo(\n 3.14\n );"
},
{
"path": "tests/asset/function.php",
"chars": 372,
"preview": "<?php\n\nnamespace DisallowFloatsInFunctionSignatures;\n\n/**\n * @param float $float\n * @param int|float $intOrFloat\n * @par"
},
{
"path": "tests/asset/functionNotAutoloaded.php",
"chars": 55,
"preview": "<?php\n\nfunction nonexistentRoaveFunction(): float\n{\n\n}\n"
},
{
"path": "tests/asset/functionWithInterpolatedFloatAndNonFloatParameters.php",
"chars": 209,
"preview": "<?php\n\nnamespace DisallowFloatsInFunctionSignatures;\n\n/** @param mixed $d */\nfunction functionWithInterpolatedFloatAndNo"
},
{
"path": "tests/asset/functionWithoutNamespace.php",
"chars": 239,
"preview": "<?php\n\n/**\n * @param float $float\n * @param int|float $intOrFloat\n * @param string $string\n * @return float\n */\nfunction"
},
{
"path": "tests/asset/method.php",
"chars": 502,
"preview": "<?php\n\nnamespace DisallowFloatsInMethodSignatures;\n\nclass Foo\n{\n\n /**\n * @param float $float\n * @param int|fl"
},
{
"path": "tests/asset/methodWithConditionalReturnType.php",
"chars": 1172,
"preview": "<?php\n\nnamespace DisallowFloatsInMethodSignatures;\n\nuse Exception;\n\nuse function gettype;\n\n/**\n * @template TObject of o"
},
{
"path": "tests/asset/methodWithInterpolatedFloatAndNotFloatParameters.php",
"chars": 219,
"preview": "<?php\n\nnamespace DisallowFloatsInMethodSignatures;\n\nclass Bar\n{\n /** @param mixed $d */\n public function doFoo(\n "
},
{
"path": "tests/asset/property.php",
"chars": 227,
"preview": "<?php\n\nnamespace DisallowFloatsInProperties;\n\nclass Foo\n{\n\n /** @var float */\n private $foo;\n\n /** @var float|i"
},
{
"path": "tests/src/DisallowFloatAssignedToVariableRuleTest.php",
"chars": 1319,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PHPStan\\Node\\Printer\\Printer;\nuse PHPSta"
},
{
"path": "tests/src/DisallowFloatEverywhereRuleTest.php",
"chars": 1133,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PHPStan\\Rules\\Rule;\nuse PHPStan\\Testing\\"
},
{
"path": "tests/src/DisallowFloatInFunctionSignatureRuleTest.php",
"chars": 3370,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PHPStan\\Rules\\Rule;\nuse PHPStan\\Testing\\"
},
{
"path": "tests/src/DisallowFloatInMethodSignatureRuleTest.php",
"chars": 3608,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PhpParser\\Node\\Stmt\\ClassMethod;\nuse PHP"
},
{
"path": "tests/src/DisallowFloatPropertyTypeRuleTest.php",
"chars": 1600,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PhpParser\\Node\\PropertyItem;\nuse PHPStan"
},
{
"path": "tests/src/ScopeWithNodeCallbackInvoker.php",
"chars": 269,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Roave\\PHPStanTest\\Rules\\Floats;\n\nuse PHPStan\\Analyser\\NodeCallbackInvoker;\nus"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the Roave/no-floaters GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (40.2 KB), approximately 10.9k tokens, and a symbol index with 70 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.