Skip to content

Commit

Permalink
Check leading and trailing file whitespace and BOM
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jun 29, 2020
1 parent 37e65a4 commit 6905d66
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 1 deletion.
1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ parameters:
closureUsesThis: true
randomIntParameters: true
nullCoalesce: true
fileWhitespace: true
5 changes: 5 additions & 0 deletions conf/config.level0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ conditionalTags:
phpstan.rules.rule: %featureToggles.closureUsesThis%
PHPStan\Rules\Missing\MissingClosureNativeReturnTypehintRule:
phpstan.rules.rule: %checkMissingClosureNativeReturnTypehintRule%
PHPStan\Rules\Whitespace\FileWhitespaceRule:
phpstan.rules.rule: %featureToggles.fileWhitespace%

parametersSchema:
missingClosureNativeReturnCheckObjectTypehint: bool()
Expand Down Expand Up @@ -178,3 +180,6 @@ services:
class: PHPStan\Rules\Regexp\RegularExpressionPatternRule
tags:
- phpstan.rules.rule

-
class: PHPStan\Rules\Whitespace\FileWhitespaceRule
4 changes: 3 additions & 1 deletion conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ parameters:
closureUsesThis: false
randomIntParameters: false
nullCoalesce: false
fileWhitespace: false
fileExtensions:
- php
checkAlwaysTrueCheckTypeFunctionCall: false
Expand Down Expand Up @@ -145,7 +146,8 @@ parametersSchema:
disableRuntimeReflectionProvider: bool(),
closureUsesThis: bool(),
randomIntParameters: bool(),
nullCoalesce: bool()
nullCoalesce: bool(),
fileWhitespace: bool()
])
fileExtensions: listOf(string())
checkAlwaysTrueCheckTypeFunctionCall: bool()
Expand Down
91 changes: 91 additions & 0 deletions src/Rules/Whitespace/FileWhitespaceRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Whitespace;

use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
use PHPStan\Node\FileNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

/**
* @implements Rule<FileNode>
*/
class FileWhitespaceRule implements Rule
{

public function getNodeType(): string
{
return FileNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
$nodes = $node->getNodes();
if (count($nodes) === 0) {
return [];
}

$firstNode = $nodes[0];
$messages = [];
if ($firstNode instanceof Node\Stmt\InlineHTML && $firstNode->value === "\xef\xbb\xbf") {
$messages[] = RuleErrorBuilder::message('File begins with UTF-8 BOM character. This may cause problems when running the code in the web browser.')->build();
}

$nodeTraverser = new NodeTraverser();
$visitor = new class () extends \PhpParser\NodeVisitorAbstract {

/** @var \PhpParser\Node[] */
private $lastNodes = [];

/**
* @param Node $node
* @return int|Node|null
*/
public function enterNode(Node $node)
{
if ($node instanceof Node\Stmt\Declare_) {
if ($node->stmts !== null && count($node->stmts) > 0) {
$this->lastNodes[] = $node->stmts[count($node->stmts) - 1];
}
return null;
}
if ($node instanceof Node\Stmt\Namespace_) {
if (count($node->stmts) > 0) {
$this->lastNodes[] = $node->stmts[count($node->stmts) - 1];
}
return null;
}
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}

/**
* @return Node[]
*/
public function getLastNodes(): array
{
return $this->lastNodes;
}

};
$nodeTraverser->addVisitor($visitor);
$nodeTraverser->traverse($nodes);

$lastNodes = $visitor->getLastNodes();
if (count($nodes) > 0) {
$lastNodes[] = $nodes[count($nodes) - 1];
}
foreach ($lastNodes as $lastNode) {
if (!$lastNode instanceof Node\Stmt\InlineHTML || Strings::match($lastNode->value, '#(\s+)#') === null) {
continue;
}

$messages[] = RuleErrorBuilder::message('File ends with a trailing whitespace. This may cause problems when running the code in the web browser. Remove the closing ?> mark or remove the whitespace.')->line($lastNode->getStartLine())->build();
}

return $messages;
}

}
54 changes: 54 additions & 0 deletions tests/PHPStan/Rules/Whitespace/FileWhitespaceRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Whitespace;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<FileWhitespaceRule>
*/
class FileWhitespaceRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new FileWhitespaceRule();
}

public function testBom(): void
{
$this->analyse([__DIR__ . '/data/bom.php'], [
[
'File begins with UTF-8 BOM character. This may cause problems when running the code in the web browser.',
1,
],
]);
}

public function testCorrectFile(): void
{
$this->analyse([__DIR__ . '/data/correct.php'], []);
}

public function testTrailingWhitespaceWithoutNamespace(): void
{
$this->analyse([__DIR__ . '/data/trailing.php'], [
[
'File ends with a trailing whitespace. This may cause problems when running the code in the web browser. Remove the closing ?> mark or remove the whitespace.',
6,
],
]);
}

public function testTrailingWhitespace(): void
{
$this->analyse([__DIR__ . '/data/trailing-namespace.php'], [
[
'File ends with a trailing whitespace. This may cause problems when running the code in the web browser. Remove the closing ?> mark or remove the whitespace.',
8,
],
]);
}

}
3 changes: 3 additions & 0 deletions tests/PHPStan/Rules/Whitespace/data/bom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

echo 'test';
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/Whitespace/data/correct.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

namespace Test;

echo 'foo';
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/Whitespace/data/trailing-namespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types = 1);

namespace Test;

echo 'foo';

?>

6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Whitespace/data/trailing.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

echo 'foo';

?>

0 comments on commit 6905d66

Please sign in to comment.