1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00
This commit is contained in:
Brown 2019-01-02 11:18:22 -05:00
parent c4d024a72d
commit 1d300ec342
9 changed files with 112 additions and 11 deletions

View File

@ -144,6 +144,7 @@
<xs:element name="DuplicateArrayKey" type="IssueHandlerType" minOccurs="0" />
<xs:element name="DuplicateParam" type="IssueHandlerType" minOccurs="0" />
<xs:element name="DuplicateClass" type="IssueHandlerType" minOccurs="0" />
<xs:element name="DuplicateMethod" type="IssueHandlerType" minOccurs="0" />
<xs:element name="EmptyArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="FalseOperand" type="IssueHandlerType" minOccurs="0" />
<xs:element name="FalsableReturnStatement" type="IssueHandlerType" minOccurs="0" />

View File

@ -180,6 +180,17 @@ class A {}
class A {}
```
### DuplicateMethod
Emitted when a method is defined twice
```php
class A {
public function foo() {}
public function foo() {}
}
```
### DuplicateParam
Emitted when a function has a param defined twice

View File

@ -497,7 +497,13 @@ class Config
}
if (isset($config_xml['autoloader'])) {
$config->autoloader = (string) $config_xml['autoloader'];
$autoloader_path = $config->base_dir . DIRECTORY_SEPARATOR . $config_xml['autoloader'];
if (!file_exists($autoloader_path)) {
throw new ConfigException('Cannot locate config schema');
}
$config->autoloader = realpath($autoloader_path);
}
if (isset($config_xml['cacheDirectory'])) {
@ -1331,7 +1337,7 @@ class Config
if ($this->autoloader) {
// do this in a separate method so scope does not leak
$this->requireAutoloader($this->base_dir . DIRECTORY_SEPARATOR . $this->autoloader);
$this->requireAutoloader($this->autoloader);
$this->collectPredefinedConstants();
$this->collectPredefinedFunctions();

View File

@ -21,6 +21,7 @@ use Psalm\Exception\IncorrectDocblockException;
use Psalm\Exception\TypeParseTreeException;
use Psalm\FileSource;
use Psalm\Issue\DuplicateClass;
use Psalm\Issue\DuplicateMethod;
use Psalm\Issue\DuplicateParam;
use Psalm\Issue\InvalidDocblock;
use Psalm\Issue\MisplacedRequiredParam;
@ -835,7 +836,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
* @param PhpParser\Node\FunctionLike $stmt
* @param bool $fake_method in the case of @method annotations we do something a little strange
*
* @return FunctionLikeStorage
* @return FunctionLikeStorage|false
*/
private function registerFunctionLike(PhpParser\Node\FunctionLike $stmt, $fake_method = false)
{
@ -889,7 +890,25 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
if (isset($class_storage->methods[strtolower($stmt->name->name)])) {
if (!$this->codebase->register_stub_files) {
throw new \InvalidArgumentException('Cannot re-register ' . $function_id);
$duplicate_method_storage = $class_storage->methods[strtolower($stmt->name->name)];
if (IssueBuffer::accepts(
new DuplicateMethod(
'Method ' . $function_id . ' has already been defined'
. ($duplicate_method_storage->location
? ' in ' . $duplicate_method_storage->location->file_path
: ''),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
$this->file_storage->has_visitor_issues = true;
$duplicate_method_storage->has_visitor_issues = true;
return false;
}
$storage = $class_storage->methods[strtolower($stmt->name->name)];

View File

@ -0,0 +1,6 @@
<?php
namespace Psalm\Issue;
class DuplicateMethod extends CodeIssue
{
}

View File

@ -4,6 +4,8 @@ namespace Psalm;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Issue\ClassIssue;
use Psalm\Issue\CodeIssue;
use Psalm\Issue\DuplicateClass;
use Psalm\Issue\DuplicateMethod;
use Psalm\Issue\MethodIssue;
use Psalm\Issue\PropertyIssue;
use Psalm\Output\Compact;
@ -61,7 +63,10 @@ class IssueBuffer
return false;
}
if (!$config->reportIssueInFile($issue_type, $e->getFilePath())) {
if (!$e instanceof DuplicateClass
&& !$e instanceof DuplicateMethod
&& !$config->reportIssueInFile($issue_type, $e->getFilePath())
) {
return false;
}

View File

@ -288,6 +288,17 @@ class ClassStringTest extends TestCase
use T;
}'
],
'refineStringToClassString' => [
'<?php
class A {}
function foo(string $s) : void {
if ($s !== A::class) {
return;
}
new $s();
}',
],
];
}

View File

@ -93,17 +93,15 @@ class ErrorAfterUpdateTest extends \Psalm\Tests\TestCase
$this->file_provider->registerFile($file_path, $contents);
}
$this->expectException('\Psalm\Exception\CodeException');
$this->expectExceptionMessageRegexp('/\b' . preg_quote($error_message, '/') . '\b/');
$codebase->reloadFiles($this->project_analyzer, array_keys($end_files));
foreach ($end_files as $file_path => $_) {
$codebase->addFilesToAnalyze([$file_path => $file_path]);
}
$codebase->scanFiles();
$this->expectException('\Psalm\Exception\CodeException');
$this->expectExceptionMessageRegexp('/\b' . preg_quote($error_message, '/') . '\b/');
$codebase->analyzer->analyzeFiles($this->project_analyzer, 1, false);
}
@ -556,6 +554,46 @@ class ErrorAfterUpdateTest extends \Psalm\Tests\TestCase
],
'error_message' => 'PropertyNotSetInConstructor'
],
'duplicateClass' => [
'file_stages' => [
[
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {}',
],
[
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {}
class A {}',
],
],
'error_message' => 'DuplicateClass'
],
'duplicateMethod' => [
'file_stages' => [
[
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public function foo() : void {}
}',
],
[
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public function foo() : void {}
public function foo() : void {}
}',
],
],
'error_message' => 'DuplicateMethod'
],
];
}
}

View File

@ -2,7 +2,7 @@
ini_set('display_startup_errors', '1');
ini_set('html_errors', '1');
ini_set('memory_limit', '-1');
ini_set('memory_limit', '4G');
error_reporting(E_ALL);
gc_disable();
@ -44,3 +44,7 @@ Psalm\Internal\Provider\StatementsProvider::parseStatements($b);
$diff_2 = microtime(true) - $time;
echo 'Full parsing: ' . number_format($diff_2, 4) . "\n";
echo strlen($a);
Psalm\Internal\Diff\FileDiffer::getDiff($a, '');