Skip to content

Commit

Permalink
Merge pull request #25 from wata727/unneeded_regexp
Browse files Browse the repository at this point in the history
Add UnneededRegularExpression
  • Loading branch information
wata727 authored Jan 2, 2018
2 parents 16e627c + 56f71e3 commit bc00e6d
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@
- [UnreachableCatch](UnreachableCatch.md)
- [DuplicateCaseCondition](DuplicateCaseCondition.md)
- [AmbiguousReturnCheck](AmbiguousReturnCheck.md)
- [UnneededRegularExpression](UnneededRegularExpression.md)
32 changes: 32 additions & 0 deletions docs/UnneededRegularExpression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# UnneededRegularExpression

Under the following conditions, using `strpos()` instead of `preg_match()` will be faster.

1. Not using `matches` variables.
2. Not using a pattern including pattern modifiers.
3. Not using a pattern including meta characters.

## Before

```php
<?php

if (preg_match("/abc/", $var)) { // UnneededRegularExpression: Using `strpos()` instead of `preg_match()` will be faster.
something($var);
}
```

## After

```php
<?php

if (strpos($var, "abc") !== false) {
something($var);
}
```


## Reference

https://secure.php.net/manual/en/function.preg-match.php
77 changes: 77 additions & 0 deletions src/Tool/UnneededRegularExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php declare(strict_types=1);

namespace Pahout\Tool;

use \ast\Node;
use Pahout\Logger;
use Pahout\Hint;

/**
* Find `preg_match()` which does not need regular expressions.
*
* Under the following conditions, using `strpos()` instead of `preg_match()` will be faster.
*
* 1. Not using `matches` variables.
* 2. Not using a pattern including pattern modifiers.
* 3. Not using a pattern including meta characters.
*
*/
class UnneededRegularExpression implements Base
{
use Howdah;

public const ENTRY_POINT = \ast\AST_CALL;
public const PHP_VERSION = '0.0.0';
public const HINT_TYPE = "UnneededRegularExpression";
private const HINT_MESSAGE = 'Using `strpos()` instead of `preg_match()` will be faster.';
private const HINT_LINK = Hint::DOCUMENT_LINK."/UnneededRegularExpression.md";

/**
* Find `preg_match()` which does not need regular expressions.
*
* @param string $file File name to be analyzed.
* @param Node $node AST node to be analyzed.
* @return Hint[] List of hints obtained from results.
*/
public function run(string $file, Node $node): array
{
if ($this->isFunctionCall($node, 'preg_match')) {
$args = $node->children['args']->children;
if (count($args) > 2) {
return [];
}

if (is_string($args[0]) && $this->isUnneededRegExp($args[0])) {
return [new Hint(
self::HINT_TYPE,
self::HINT_MESSAGE,
$file,
$node->lineno,
self::HINT_LINK
)];
}
}

return [];
}

/**
* Check whether it is a regular expression pattern that can use `strpos()`.
*
* The following pattern returns false:
*
* 1. Including pattern modifiers.
* 2. Including meta characters.
*
* @param string $str A regular expression pattern for testing.
* @return boolean The result of testing.
*/
private function isUnneededRegExp(string $str): Bool
{
if (substr($str, -1) !== "/") {
return false;
}

return $str === preg_quote($str);
}
}
1 change: 1 addition & 0 deletions src/ToolBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ToolBox
'UnreachableCatch',
'DuplicateCaseCondition',
'AmbiguousReturnCheck',
'UnneededRegularExpression',
];

/**
Expand Down
95 changes: 95 additions & 0 deletions tests/Tool/UnneededRegularExpressionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace Pahout\Test\Tool;

use PHPUnit\Framework\TestCase;
use Pahout\Test\helper\PahoutHelper;
use Pahout\Tool\UnneededRegularExpression;
use Pahout\Hint;
use Pahout\Logger;
use Pahout\Config;
use Symfony\Component\Console\Output\ConsoleOutput;

class UnneededRegularExpressionTest extends TestCase
{
public function setUp()
{
Logger::getInstance(new ConsoleOutput());
}

public function test_unneeded_regular_expression()
{
$code = <<<'CODE'
<?php
if (preg_match("/abc/", $var)) {
something($var);
}
CODE;
$root = \ast\parse_code($code, Config::AST_VERSION);

$tester = PahoutHelper::create(new UnneededRegularExpression());
$tester->test($root);

$this->assertEquals(
[
new Hint(
'UnneededRegularExpression',
'Using `strpos()` instead of `preg_match()` will be faster.',
'./test.php',
2,
Hint::DOCUMENT_LINK.'/UnneededRegularExpression.md'
)
],
$tester->hints
);
}

public function test_using_complex_regular_expression()
{
$code = <<<'CODE'
<?php
if (preg_match("/^[a-z]$/", $var)) {
something($var);
}
CODE;
$root = \ast\parse_code($code, Config::AST_VERSION);

$tester = PahoutHelper::create(new UnneededRegularExpression());
$tester->test($root);

$this->assertEmpty($tester->hints);
}


public function test_using_match_value()
{
$code = <<<'CODE'
<?php
if (preg_match("/abc/", $var, $match)) {
something($var);
}
CODE;
$root = \ast\parse_code($code, Config::AST_VERSION);

$tester = PahoutHelper::create(new UnneededRegularExpression());
$tester->test($root);

$this->assertEmpty($tester->hints);
}

public function test_using_pattern_modifier()
{
$code = <<<'CODE'
<?php
if (preg_match("/abc/i", $var, $match)) {
something($var);
}
CODE;
$root = \ast\parse_code($code, Config::AST_VERSION);

$tester = PahoutHelper::create(new UnneededRegularExpression());
$tester->test($root);

$this->assertEmpty($tester->hints);
}
}

0 comments on commit bc00e6d

Please sign in to comment.