mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix #1150
This commit is contained in:
parent
c4d024a72d
commit
1d300ec342
@ -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" />
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)];
|
||||
|
6
src/Psalm/Issue/DuplicateMethod.php
Normal file
6
src/Psalm/Issue/DuplicateMethod.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class DuplicateMethod extends CodeIssue
|
||||
{
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -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'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -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, '');
|
||||
|
Loading…
Reference in New Issue
Block a user