exussum12 /
coverageChecker
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | namespace exussum12\CoverageChecker; |
||
| 3 | |||
| 4 | use PhpParser\Node; |
||
| 5 | use PhpParser\Parser; |
||
| 6 | use PhpParser\ParserFactory; |
||
| 7 | |||
| 8 | class FileParser |
||
| 9 | { |
||
| 10 | protected $sourceCode = ''; |
||
| 11 | protected $classes = []; |
||
| 12 | protected $functions = []; |
||
| 13 | |||
| 14 | public function __construct($sourceCode) |
||
| 15 | { |
||
| 16 | $this->sourceCode = $sourceCode; |
||
| 17 | $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); |
||
| 18 | $this->parse($parser); |
||
| 19 | } |
||
| 20 | |||
| 21 | /** |
||
| 22 | * @return CodeLimits[] |
||
| 23 | */ |
||
| 24 | public function getClassLimits() |
||
| 25 | { |
||
| 26 | return $this->classes; |
||
| 27 | } |
||
| 28 | |||
| 29 | /** |
||
| 30 | * @return CodeLimits[] |
||
| 31 | */ |
||
| 32 | public function getFunctionLimits() |
||
| 33 | { |
||
| 34 | return $this->functions; |
||
| 35 | } |
||
| 36 | |||
| 37 | protected function parse(Parser $parser) |
||
| 38 | { |
||
| 39 | $ast = $parser->parse($this->sourceCode); |
||
| 40 | foreach ($ast as $node) { |
||
|
0 ignored issues
–
show
|
|||
| 41 | $this->handleNode($node); |
||
| 42 | } |
||
| 43 | } |
||
| 44 | |||
| 45 | protected function getCodeLimits(Node $node) |
||
| 46 | { |
||
| 47 | $startLine = $node->getAttribute('startLine'); |
||
| 48 | $endLine = $node->getAttribute('endLine'); |
||
| 49 | if ($node->getDocComment()) { |
||
| 50 | $startLine = $node->getDocComment()->getLine(); |
||
| 51 | } |
||
| 52 | |||
| 53 | return new CodeLimits($startLine, $endLine); |
||
| 54 | } |
||
| 55 | |||
| 56 | protected function addClass($classLimits) |
||
| 57 | { |
||
| 58 | $this->classes[] = $classLimits; |
||
| 59 | } |
||
| 60 | |||
| 61 | protected function addFunction($classLimits) |
||
| 62 | { |
||
| 63 | $this->functions[] = $classLimits; |
||
| 64 | } |
||
| 65 | |||
| 66 | protected function handleClass(Node $node) |
||
| 67 | { |
||
| 68 | $this->addClass($this->getCodeLimits($node)); |
||
| 69 | |||
| 70 | foreach ($node->getMethods() as $function) { |
||
|
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
PhpParser\Node as the method getMethods() does only exist in the following implementations of said interface: PhpParser\Node\Stmt\ClassLike, PhpParser\Node\Stmt\Class_, PhpParser\Node\Stmt\Interface_, PhpParser\Node\Stmt\Trait_.
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
| 71 | $this->handleNode($function); |
||
| 72 | } |
||
| 73 | } |
||
| 74 | |||
| 75 | protected function handleFunction(Node $node) |
||
| 76 | { |
||
| 77 | $this->addFunction($this->getCodeLimits($node)); |
||
| 78 | } |
||
| 79 | |||
| 80 | private function handleNamespace(Node $node) |
||
| 81 | { |
||
| 82 | foreach ($node->stmts as $part) { |
||
|
0 ignored issues
–
show
Accessing
stmts on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
| 83 | $this->handleNode($part); |
||
| 84 | } |
||
| 85 | } |
||
| 86 | |||
| 87 | /** |
||
| 88 | * @param $node |
||
| 89 | */ |
||
| 90 | protected function handleNode($node) |
||
| 91 | { |
||
| 92 | $type = $node->getType(); |
||
| 93 | if ($type == 'Stmt_Namespace') { |
||
| 94 | $this->handleNamespace($node); |
||
| 95 | } |
||
| 96 | |||
| 97 | if ($type == 'Stmt_Class') { |
||
| 98 | $this->handleClass($node); |
||
| 99 | } |
||
| 100 | |||
| 101 | if ($type == "Stmt_Function" || $type == "Stmt_ClassMethod") { |
||
| 102 | $this->handleFunction($node); |
||
| 103 | } |
||
| 104 | } |
||
| 105 | } |
||
| 106 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.