1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Add extra issue for invalid clone and fix issue reporting;

This commit is contained in:
Matthew Brown 2017-01-16 12:59:09 -05:00
parent 4b283564ca
commit e3a9cb98c3
11 changed files with 67 additions and 27 deletions

View File

@ -85,6 +85,7 @@
<xs:element name="InvalidArrayAccess" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidArrayAssignment" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidArrayAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidClass" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidClass" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidClone" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidParamDefault" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidParamDefault" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidDocblock" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidDocblock" type="IssueHandlerType" minOccurs="0" />
<xs:element name="InvalidFunctionCall" type="IssueHandlerType" minOccurs="0" /> <xs:element name="InvalidFunctionCall" type="IssueHandlerType" minOccurs="0" />

View File

@ -472,7 +472,7 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
$global_context ? clone $global_context : null $global_context ? clone $global_context : null
); );
if (!$config->excludeIssueInFile('InvalidReturnType', $source->getFileName())) { if (!$config->excludeIssueInFile('InvalidReturnType', $source->getFilePath())) {
$return_type_location = null; $return_type_location = null;
$secondary_return_type_location = null; $secondary_return_type_location = null;

View File

@ -307,7 +307,7 @@ class FileChecker extends SourceChecker implements StatementsSource
$function_context = new Context($this->file_name, $this->context->self); $function_context = new Context($this->file_name, $this->context->self);
$function_checker->analyze($function_context, $this->context); $function_checker->analyze($function_context, $this->context);
if (!$config->excludeIssueInFile('InvalidReturnType', $this->file_name)) { if (!$config->excludeIssueInFile('InvalidReturnType', $this->file_path)) {
/** @var string */ /** @var string */
$method_id = $function_checker->getMethodId(); $method_id = $function_checker->getMethodId();

View File

@ -955,11 +955,11 @@ class CallChecker
if ($function_params !== null) { if ($function_params !== null) {
$by_ref = $argument_offset < count($function_params) $by_ref = $argument_offset < count($function_params)
? $function_params[$argument_offset]->by_ref ? $function_params[$argument_offset]->by_ref
: $last_param->is_variadic && $last_param->by_ref; : $last_param && $last_param->is_variadic && $last_param->by_ref;
$by_ref_type = null; $by_ref_type = null;
if ($by_ref) { if ($by_ref && $last_param) {
$by_ref_type = $argument_offset < count($function_params) $by_ref_type = $argument_offset < count($function_params)
? clone $function_params[$argument_offset]->type ? clone $function_params[$argument_offset]->type
: clone $last_param->type; : clone $last_param->type;
@ -992,11 +992,11 @@ class CallChecker
if ($function_params !== null) { if ($function_params !== null) {
$by_ref = $argument_offset < count($function_params) $by_ref = $argument_offset < count($function_params)
? $function_params[$argument_offset]->by_ref ? $function_params[$argument_offset]->by_ref
: $last_param->is_variadic && $last_param->by_ref; : $last_param && $last_param->is_variadic && $last_param->by_ref;
$by_ref_type = null; $by_ref_type = null;
if ($by_ref) { if ($by_ref && $last_param) {
$by_ref_type = $argument_offset < count($function_params) $by_ref_type = $argument_offset < count($function_params)
? clone $function_params[$argument_offset]->type ? clone $function_params[$argument_offset]->type
: clone $last_param->type; : clone $last_param->type;

View File

@ -17,6 +17,7 @@ use Psalm\CodeLocation;
use Psalm\Config; use Psalm\Config;
use Psalm\Context; use Psalm\Context;
use Psalm\Issue\ForbiddenCode; use Psalm\Issue\ForbiddenCode;
use Psalm\Issue\InvalidClone;
use Psalm\Issue\InvalidOperand; use Psalm\Issue\InvalidOperand;
use Psalm\Issue\InvalidScope; use Psalm\Issue\InvalidScope;
use Psalm\Issue\InvalidStaticVariable; use Psalm\Issue\InvalidStaticVariable;
@ -305,13 +306,7 @@ class ExpressionChecker
$stmt->inferredType = Type::getNull(); $stmt->inferredType = Type::getNull();
} elseif ($stmt instanceof PhpParser\Node\Expr\Clone_) { } elseif ($stmt instanceof PhpParser\Node\Expr\Clone_) {
if (self::analyze($statements_checker, $stmt->expr, $context) === false) { self::analyzeClone($statements_checker, $stmt, $context);
return false;
}
if (property_exists($stmt->expr, 'inferredType')) {
$stmt->inferredType = $stmt->expr->inferredType;
}
} elseif ($stmt instanceof PhpParser\Node\Expr\Instanceof_) { } elseif ($stmt instanceof PhpParser\Node\Expr\Instanceof_) {
if (self::analyze($statements_checker, $stmt->expr, $context) === false) { if (self::analyze($statements_checker, $stmt->expr, $context) === false) {
return false; return false;
@ -1686,6 +1681,42 @@ class ExpressionChecker
} }
} }
/**
* @param StatementsChecker $statements_checker
* @param PhpParser\Node\Expr\Clone_ $stmt
* @param Context $context
* @return false|null
*/
protected static function analyzeClone(
StatementsChecker $statements_checker,
PhpParser\Node\Expr\Clone_ $stmt,
Context $context
) {
if (self::analyze($statements_checker, $stmt->expr, $context) === false) {
return false;
}
if (isset($stmt->expr->inferredType)) {
foreach ($stmt->expr->inferredType->types as $clone_type_part) {
if (!$clone_type_part instanceof TNamedObject && !$clone_type_part instanceof TObject) {
if (IssueBuffer::accepts(
new InvalidClone(
'Cannot clone ' . $clone_type_part,
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
return;
}
}
$stmt->inferredType = $stmt->expr->inferredType;
}
}
/** /**
* @param string $fq_class_name * @param string $fq_class_name
* @return boolean * @return boolean

View File

@ -186,7 +186,7 @@ class StatementsChecker extends SourceChecker implements StatementsSource
$config = Config::getInstance(); $config = Config::getInstance();
if (!$config->excludeIssueInFile('InvalidReturnType', $this->getFileName())) { if (!$config->excludeIssueInFile('InvalidReturnType', $this->getFilePath())) {
/** @var string */ /** @var string */
$method_id = $function_checkers[$stmt->name]->getMethodId(); $method_id = $function_checkers[$stmt->name]->getMethodId();

View File

@ -422,24 +422,22 @@ class Config
/** /**
* @param string $issue_type * @param string $issue_type
* @param string $file_name * @param string $file_path
* @return bool * @return bool
*/ */
public function excludeIssueInFile($issue_type, $file_name) public function excludeIssueInFile($issue_type, $file_path)
{ {
if (!$this->totally_typed && in_array($issue_type, self::$MIXED_ISSUES)) { if (!$this->totally_typed && in_array($issue_type, self::$MIXED_ISSUES)) {
return true; return true;
} }
$file_name = $this->shortenFileName($file_name);
if ($this->project_files && $this->hide_external_errors) { if ($this->project_files && $this->hide_external_errors) {
if (!$this->isInProjectDirs($file_name)) { if (!$this->isInProjectDirs($file_path)) {
return true; return true;
} }
} }
if ($this->getReportingLevelForFile($issue_type, $file_name) === self::REPORT_SUPPRESS) { if ($this->getReportingLevelForFile($issue_type, $file_path) === self::REPORT_SUPPRESS) {
return true; return true;
} }
@ -452,18 +450,21 @@ class Config
*/ */
public function isInProjectDirs($file_path) public function isInProjectDirs($file_path)
{ {
if ($file_path[0] !== '/') {
throw new \UnexpectedValueException('eesh');
}
return $this->project_files && $this->project_files->allows($file_path); return $this->project_files && $this->project_files->allows($file_path);
} }
/** /**
* @param string $issue_type * @param string $issue_type
* @param string $file_name * @param string $file_path
* @return string * @return string
*/ */
public function getReportingLevelForFile($issue_type, $file_name) public function getReportingLevelForFile($issue_type, $file_path)
{ {
if (isset($this->issue_handlers[$issue_type])) { if (isset($this->issue_handlers[$issue_type])) {
return $this->issue_handlers[$issue_type]->getReportingLevelForFile($file_name); return $this->issue_handlers[$issue_type]->getReportingLevelForFile($file_path);
} }
return self::REPORT_ERROR; return self::REPORT_ERROR;

View File

@ -13,6 +13,7 @@ class ErrorLevelFileFilter extends FileFilter
/** /**
* @param SimpleXMLElement $e * @param SimpleXMLElement $e
* @param Config $config
* @param bool $inclusive * @param bool $inclusive
* @return self * @return self
*/ */

View File

@ -55,13 +55,13 @@ class IssueHandler
} }
/** /**
* @param string $file_name * @param string $file_path
* @return string * @return string
*/ */
public function getReportingLevelForFile($file_name) public function getReportingLevelForFile($file_path)
{ {
foreach ($this->custom_levels as $custom_level) { foreach ($this->custom_levels as $custom_level) {
if ($custom_level->allows($file_name)) { if ($custom_level->allows($file_path)) {
return $custom_level->getErrorLevel(); return $custom_level->getErrorLevel();
} }
} }

View File

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

View File

@ -41,7 +41,7 @@ class IssueBuffer
return false; return false;
} }
if ($config->excludeIssueInFile($issue_type, $e->getFileName())) { if ($config->excludeIssueInFile($issue_type, $e->getFilePath())) {
return false; return false;
} }