1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-15 02:47:02 +01:00
psalm/src/Psalm/Checker/StatementsChecker.php

1184 lines
42 KiB
PHP
Raw Normal View History

<?php
namespace Psalm\Checker;
2016-02-04 15:22:46 +01:00
use PhpParser;
2016-10-22 23:35:59 +02:00
use Psalm\Checker\Statements\Block\ForChecker;
2016-10-22 19:23:18 +02:00
use Psalm\Checker\Statements\Block\ForeachChecker;
use Psalm\Checker\Statements\Block\IfChecker;
2016-10-22 19:37:06 +02:00
use Psalm\Checker\Statements\Block\SwitchChecker;
2016-10-22 23:35:59 +02:00
use Psalm\Checker\Statements\Block\TryChecker;
use Psalm\Checker\Statements\Block\WhileChecker;
2016-11-01 16:37:58 +01:00
use Psalm\Checker\Statements\Expression\AssignmentChecker;
use Psalm\Checker\Statements\Expression\CallChecker;
use Psalm\Checker\Statements\ExpressionChecker;
use Psalm\CodeLocation;
2016-11-02 07:29:00 +01:00
use Psalm\Config;
use Psalm\Context;
use Psalm\Exception\FileIncludeException;
use Psalm\FileManipulation\FileManipulationBuffer;
use Psalm\Issue\ContinueOutsideLoop;
use Psalm\Issue\InvalidGlobal;
2017-10-29 22:36:02 +01:00
use Psalm\Issue\MissingFile;
use Psalm\Issue\UnevaluatedCode;
2016-11-06 01:53:39 +01:00
use Psalm\Issue\UnrecognizedStatement;
use Psalm\Issue\UnresolvableInclude;
2016-11-02 07:29:00 +01:00
use Psalm\IssueBuffer;
use Psalm\StatementsSource;
2016-10-22 19:23:18 +02:00
use Psalm\Type;
2017-01-07 20:35:07 +01:00
class StatementsChecker extends SourceChecker implements StatementsSource
{
/**
* @var StatementsSource
*/
2016-08-11 00:10:12 +02:00
protected $source;
/**
* @var FileChecker
*/
protected $file_checker;
2016-11-01 05:39:41 +01:00
/**
* @var array<string, CodeLocation>
2016-11-01 05:39:41 +01:00
*/
private $all_vars = [];
2016-11-01 05:39:41 +01:00
2017-07-27 01:54:22 +02:00
/**
* @var array<string, Type\Union>
*/
public static $stub_constants = [];
/**
* @var array<string, FunctionChecker>
*/
private $function_checkers = [];
2016-11-02 07:29:00 +01:00
/**
* @param StatementsSource $source
*/
2016-10-18 22:28:51 +02:00
public function __construct(StatementsSource $source)
{
2016-08-11 00:10:12 +02:00
$this->source = $source;
$this->file_checker = $source->getFileChecker();
}
2016-06-18 20:45:55 +02:00
/**
* Checks an array of statements for validity
*
2016-12-12 19:50:46 +01:00
* @param array<PhpParser\Node\Stmt|PhpParser\Node\Expr> $stmts
* @param Context $context
* @param Context|null $loop_context
* @param Context|null $global_context
2017-05-27 02:16:18 +02:00
*
2016-06-18 20:45:55 +02:00
* @return null|false
*/
public function analyze(
2017-01-07 20:35:07 +01:00
array $stmts,
Context $context,
Context $loop_context = null,
Context $global_context = null
) {
$has_returned = false;
2016-08-15 06:58:30 +02:00
// hoist functions to the top
foreach ($stmts as $stmt) {
if ($stmt instanceof PhpParser\Node\Stmt\Function_) {
$function_checker = new FunctionChecker($stmt, $this->source);
$this->function_checkers[strtolower($stmt->name)] = $function_checker;
2016-08-15 06:58:30 +02:00
}
}
$project_checker = $this->getFileChecker()->project_checker;
$plugins = Config::getInstance()->getPlugins();
foreach ($stmts as $stmt) {
2016-11-02 07:29:00 +01:00
if ($has_returned && !($stmt instanceof PhpParser\Node\Stmt\Nop) &&
2017-01-07 20:35:07 +01:00
!($stmt instanceof PhpParser\Node\Stmt\InlineHTML)
) {
if ($context->collect_references) {
if (IssueBuffer::accepts(
new UnevaluatedCode(
'Expressions after return/throw/continue',
new CodeLocation($this->source, $stmt)
),
$this->source->getSuppressedIssues()
)) {
return false;
}
}
break;
}
2017-01-26 01:09:31 +01:00
/*
2017-03-13 23:06:56 +01:00
if (isset($context->vars_in_scope['$failed_reconciliation']) && !$stmt instanceof PhpParser\Node\Stmt\Nop) {
var_dump($stmt->getLine() . ' ' . $context->vars_in_scope['$failed_reconciliation']);
}
2017-01-26 01:09:31 +01:00
*/
$new_issues = null;
if ($docblock = $stmt->getDocComment()) {
$comments = CommentChecker::parseDocComment((string)$docblock);
if (isset($comments['specials']['psalm-suppress'])) {
$suppressed = array_filter(
array_map(
/**
* @param string $line
*
* @return string
*/
function ($line) {
return explode(' ', trim($line))[0];
},
$comments['specials']['psalm-suppress']
)
);
if ($suppressed) {
$new_issues = array_diff($suppressed, $this->source->getSuppressedIssues());
/** @psalm-suppress TypeCoercion */
$this->addSuppressedIssues($new_issues);
}
}
}
if ($stmt instanceof PhpParser\Node\Stmt\If_) {
IfChecker::analyze($this, $stmt, $context, $loop_context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {
TryChecker::analyze($this, $stmt, $context, $loop_context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\For_) {
ForChecker::analyze($this, $stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Foreach_) {
ForeachChecker::analyze($this, $stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\While_) {
WhileChecker::analyze($this, $stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Do_) {
$this->analyzeDo($stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Const_) {
$this->analyzeConstAssignment($stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Unset_) {
2016-09-17 17:57:44 +02:00
foreach ($stmt->vars as $var) {
ExpressionChecker::analyze($this, $var, $context);
2016-11-02 07:29:00 +01:00
$var_id = ExpressionChecker::getArrayVarId(
$var,
2017-01-07 20:35:07 +01:00
$this->getFQCLN(),
$this
2016-11-02 07:29:00 +01:00
);
2016-09-17 17:57:44 +02:00
if ($var_id) {
$context->remove($var_id);
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Return_) {
$has_returned = true;
$this->analyzeReturn($project_checker, $stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Throw_) {
$has_returned = true;
$this->analyzeThrow($stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Switch_) {
SwitchChecker::analyze($this, $stmt, $context, $loop_context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Break_) {
// do nothing
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Continue_) {
if ($loop_context === null) {
if (IssueBuffer::accepts(
2016-11-02 07:29:00 +01:00
new ContinueOutsideLoop(
'Continue call outside loop context',
new CodeLocation($this->source, $stmt)
2016-11-02 07:29:00 +01:00
),
2017-01-07 20:35:07 +01:00
$this->source->getSuppressedIssues()
)) {
return false;
}
}
$has_returned = true;
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Static_) {
$this->analyzeStatic($stmt, $context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Echo_) {
foreach ($stmt->exprs as $i => $expr) {
ExpressionChecker::analyze($this, $expr, $context);
if (isset($expr->inferredType)) {
if (CallChecker::checkFunctionArgumentType(
$this,
$expr->inferredType,
Type::getString(),
'echo',
2016-12-09 19:27:59 +01:00
(int)$i,
new CodeLocation($this->getSource(), $expr)
) === false) {
return false;
}
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) {
if (!$project_checker->register_global_functions) {
$function_id = strtolower($stmt->name);
$function_context = new Context($context->self);
$function_context->collect_references = $project_checker->collect_references;
$this->function_checkers[$function_id]->analyze($function_context, $context);
$config = Config::getInstance();
if ($config->reportIssueInFile('InvalidReturnType', $this->getFilePath())) {
/** @var string */
$method_id = $this->function_checkers[$function_id]->getMethodId();
$function_storage = FunctionChecker::getStorage(
$this,
$method_id
);
$return_type = $function_storage->return_type;
$return_type_location = $function_storage->return_type_location;
$this->function_checkers[$function_id]->verifyReturnType(
$project_checker,
$return_type,
$this->getFQCLN(),
$return_type_location
);
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Expr) {
if (ExpressionChecker::analyze($this, $stmt, $context) === false) {
return false;
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\InlineHTML) {
// do nothing
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Global_) {
if (!$context->collect_initializations && !$global_context) {
if (IssueBuffer::accepts(
new InvalidGlobal(
'Cannot use global scope here',
new CodeLocation($this->source, $stmt)
),
2017-01-07 20:35:07 +01:00
$this->source->getSuppressedIssues()
)) {
// fall through
}
}
foreach ($stmt->vars as $var) {
if ($var instanceof PhpParser\Node\Expr\Variable) {
if (is_string($var->name)) {
$var_id = '$' . $var->name;
$context->vars_in_scope[$var_id] =
$global_context && $global_context->hasVariable($var_id)
? clone $global_context->vars_in_scope[$var_id]
: Type::getMixed();
$context->vars_possibly_in_scope[$var_id] = true;
} else {
ExpressionChecker::analyze($this, $var, $context);
}
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Property) {
2016-01-26 20:11:56 +01:00
foreach ($stmt->props as $prop) {
if ($prop->default) {
ExpressionChecker::analyze($this, $prop->default, $context);
2016-06-24 00:45:46 +02:00
if (isset($prop->default->inferredType)) {
if (!$stmt->isStatic()) {
if (AssignmentChecker::analyzePropertyAssignment(
2016-11-02 07:29:00 +01:00
$this,
$prop,
$prop->name,
2016-12-07 00:27:22 +01:00
$prop->default,
2016-11-02 07:29:00 +01:00
$prop->default->inferredType,
$context
) === false) {
// fall through
}
2016-06-24 00:45:46 +02:00
}
}
2016-01-26 20:11:56 +01:00
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) {
$const_visibility = \ReflectionProperty::IS_PUBLIC;
if ($stmt->isProtected()) {
$const_visibility = \ReflectionProperty::IS_PROTECTED;
}
if ($stmt->isPrivate()) {
$const_visibility = \ReflectionProperty::IS_PRIVATE;
}
foreach ($stmt->consts as $const) {
ExpressionChecker::analyze($this, $const->value, $context);
if (isset($const->value->inferredType) && !$const->value->inferredType->isMixed()) {
2016-11-02 07:29:00 +01:00
ClassLikeChecker::setConstantType(
$project_checker,
2017-01-07 20:35:07 +01:00
(string)$this->getFQCLN(),
2016-11-02 07:29:00 +01:00
$const->name,
$const->value->inferredType,
$const_visibility
2016-11-02 07:29:00 +01:00
);
}
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Class_) {
$class_checker = (new ClassChecker($stmt, $this->source, $stmt->name));
$class_checker->analyze(null, $global_context);
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Nop) {
2017-03-02 04:27:52 +01:00
if ((string)$stmt->getDocComment()) {
$var_comment = CommentChecker::getTypeFromComment(
2017-03-02 04:27:52 +01:00
(string)$stmt->getDocComment(),
$context,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->getSource(),
$this->getSource()->getAliases()
2017-03-02 04:27:52 +01:00
);
if ($var_comment && $var_comment->var_id) {
$comment_type = ExpressionChecker::fleshOutType(
$project_checker,
Type::parseString($var_comment->type),
$context->self
);
$context->vars_in_scope[$var_comment->var_id] = $comment_type;
}
2017-03-02 04:27:52 +01:00
}
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Goto_) {
2016-10-22 19:23:18 +02:00
// do nothing
2016-11-02 07:29:00 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Label) {
2016-10-22 19:23:18 +02:00
// do nothing
2016-11-20 08:52:34 +01:00
} elseif ($stmt instanceof PhpParser\Node\Stmt\Declare_) {
// do nothing
2016-11-02 07:29:00 +01:00
} else {
2016-11-06 01:53:39 +01:00
if (IssueBuffer::accepts(
new UnrecognizedStatement(
'Psalm does not understand ' . get_class($stmt),
new CodeLocation($this->source, $stmt)
2016-11-06 01:53:39 +01:00
),
$this->getSuppressedIssues()
)) {
return false;
}
}
if ($plugins) {
$file_manipulations = [];
$code_location = new CodeLocation($this->source, $stmt);
foreach ($plugins as $plugin) {
if ($plugin->afterStatementCheck(
$this,
$stmt,
$context,
$code_location,
$this->getSuppressedIssues(),
$file_manipulations
) === false) {
return false;
}
}
if ($file_manipulations) {
FileManipulationBuffer::add($this->getFilePath(), $file_manipulations);
}
}
if ($new_issues) {
/** @psalm-suppress TypeCoercion */
$this->removeSuppressedIssues($new_issues);
}
}
2016-11-02 07:29:00 +01:00
return null;
}
2017-03-13 23:06:56 +01:00
/**
* Checks an array of statements in a loop
*
* @param array<PhpParser\Node\Stmt|PhpParser\Node\Expr> $stmts
* @param array<int, string> $asserted_vars
2017-03-13 23:06:56 +01:00
* @param Context $loop_context
* @param Context $outer_context
2017-05-27 02:16:18 +02:00
*
2017-03-13 23:06:56 +01:00
* @return void
*/
public function analyzeLoop(
array $stmts,
array $asserted_vars,
2017-03-13 23:06:56 +01:00
Context $loop_context,
Context $outer_context
) {
$traverser = new PhpParser\NodeTraverser;
2017-03-13 23:06:56 +01:00
$assignment_mapper = new \Psalm\Visitor\AssignmentMapVisitor($loop_context->self);
$traverser->addVisitor($assignment_mapper);
2017-03-13 23:06:56 +01:00
$traverser->traverse($stmts);
$assignment_map = $assignment_mapper->getAssignmentMap();
$assignment_depth = 0;
if ($assignment_map) {
$first_var_id = array_keys($assignment_map)[0];
$assignment_depth = self::getAssignmentMapDepth($first_var_id, $assignment_map);
}
if ($assignment_depth === 0) {
$this->analyze($stmts, $loop_context, $outer_context);
} else {
// record all the vars that existed before we did the first pass through the loop
$pre_loop_context = clone $loop_context;
$pre_outer_context = clone $outer_context;
IssueBuffer::startRecording();
$this->analyze($stmts, $loop_context, $outer_context);
$recorded_issues = IssueBuffer::clearRecordingLevel();
IssueBuffer::stopRecording();
2017-05-27 02:05:57 +02:00
for ($i = 0; $i < $assignment_depth; ++$i) {
2017-03-13 23:06:56 +01:00
$vars_to_remove = [];
$has_changes = false;
2017-03-13 23:06:56 +01:00
foreach ($loop_context->vars_in_scope as $var_id => $type) {
2017-05-27 02:05:57 +02:00
if (in_array($var_id, $asserted_vars, true)) {
// set the vars to whatever the while/foreach loop expects them to be
if ((string)$type !== (string)$pre_loop_context->vars_in_scope[$var_id]) {
$loop_context->vars_in_scope[$var_id] = $pre_loop_context->vars_in_scope[$var_id];
$has_changes = true;
}
} elseif (isset($pre_outer_context->vars_in_scope[$var_id])) {
$pre_outer = (string)$pre_outer_context->vars_in_scope[$var_id];
if ((string)$type !== $pre_outer ||
(string)$outer_context->vars_in_scope[$var_id] !== $pre_outer
) {
$has_changes = true;
2017-03-13 23:06:56 +01:00
// widen the foreach context type with the initial context type
2017-03-13 23:06:56 +01:00
$loop_context->vars_in_scope[$var_id] = Type::combineUnionTypes(
$loop_context->vars_in_scope[$var_id],
$outer_context->vars_in_scope[$var_id]
);
// if there's a change, invalidate related clauses
$pre_loop_context->removeVarFromConflictingClauses($var_id);
2017-03-13 23:06:56 +01:00
}
} else {
$vars_to_remove[] = $var_id;
}
}
2017-03-15 16:38:23 +01:00
foreach ($asserted_vars as $var_id) {
if (!isset($loop_context->vars_in_scope[$var_id])) {
$loop_context->vars_in_scope[$var_id] = $pre_loop_context->vars_in_scope[$var_id];
}
}
// if there are no changes to the types, no need to re-examine
if (!$has_changes) {
break;
}
2017-03-13 23:06:56 +01:00
// remove vars that were defined in the foreach
foreach ($vars_to_remove as $var_id) {
unset($loop_context->vars_in_scope[$var_id]);
}
$loop_context->clauses = $pre_loop_context->clauses;
2017-03-13 23:06:56 +01:00
IssueBuffer::startRecording();
$this->analyze($stmts, $loop_context, $outer_context);
$recorded_issues = IssueBuffer::clearRecordingLevel();
IssueBuffer::stopRecording();
}
2017-03-13 23:06:56 +01:00
if ($recorded_issues) {
foreach ($recorded_issues as $recorded_issue) {
// if we're not in any loops then this will just result in the issue being emitted
IssueBuffer::bubbleUp($recorded_issue);
}
}
}
}
/**
* @param string $first_var_id
* @param array<string, array<string, bool>> $assignment_map
2017-05-27 02:16:18 +02:00
*
* @return int
*/
private static function getAssignmentMapDepth($first_var_id, array $assignment_map)
{
$max_depth = 0;
$assignment_var_ids = $assignment_map[$first_var_id];
unset($assignment_map[$first_var_id]);
foreach ($assignment_var_ids as $assignment_var_id => $_) {
$depth = 1;
if (isset($assignment_map[$assignment_var_id])) {
$depth = 1 + self::getAssignmentMapDepth($assignment_var_id, $assignment_map);
}
if ($depth > $max_depth) {
$max_depth = $depth;
}
}
return $max_depth;
}
/**
2016-11-02 07:29:00 +01:00
* @param PhpParser\Node\Stmt\Static_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return false|null
*/
private function analyzeStatic(PhpParser\Node\Stmt\Static_ $stmt, Context $context)
{
2016-10-22 19:23:18 +02:00
foreach ($stmt->vars as $var) {
if ($var->default) {
if (ExpressionChecker::analyze($this, $var->default, $context) === false) {
2016-10-22 19:23:18 +02:00
return false;
}
}
2016-10-22 19:23:18 +02:00
if ($context->check_variables) {
$context->vars_in_scope['$' . $var->name] = Type::getMixed();
2016-10-22 19:23:18 +02:00
$context->vars_possibly_in_scope['$' . $var->name] = true;
$this->registerVariable('$' . $var->name, new CodeLocation($this, $stmt));
2016-10-22 19:23:18 +02:00
}
}
2016-11-02 07:29:00 +01:00
return null;
2016-10-22 19:23:18 +02:00
}
2016-10-22 19:23:18 +02:00
/**
2016-11-02 07:29:00 +01:00
* @param PhpParser\Node\Expr $stmt
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
* @param array<string, Type\Union> $existing_class_constants
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return Type\Union|null
2016-10-22 19:23:18 +02:00
*/
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
public static function getSimpleType(
PhpParser\Node\Expr $stmt,
StatementsSource $statements_source = null,
array $existing_class_constants = []
) {
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) {
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) {
return Type::getString();
}
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalAnd
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\LogicalOr
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Equal
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotEqual
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\NotIdentical
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Greater
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Smaller
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual
) {
return Type::getBool();
}
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Coalesce) {
return null;
}
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Spaceship) {
return Type::getInt();
}
$stmt->left->inferredType = self::getSimpleType(
$stmt->left,
$statements_source,
$existing_class_constants
);
$stmt->right->inferredType = self::getSimpleType(
$stmt->right,
$statements_source,
$existing_class_constants
);
if (!$stmt->left->inferredType || !$stmt->right->inferredType) {
return null;
}
if (!$statements_source) {
return null;
}
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Plus ||
$stmt instanceof PhpParser\Node\Expr\BinaryOp\Minus ||
$stmt instanceof PhpParser\Node\Expr\BinaryOp\Mod ||
$stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul ||
$stmt instanceof PhpParser\Node\Expr\BinaryOp\Pow
) {
ExpressionChecker::analyzeNonDivArithmenticOp(
$statements_source,
$stmt->left,
$stmt->right,
$stmt,
$result_type
);
if ($result_type) {
return $result_type;
}
return null;
}
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Div
&& ($stmt->left->inferredType->hasInt() || $stmt->left->inferredType->hasFloat())
&& ($stmt->right->inferredType->hasInt() || $stmt->right->inferredType->hasFloat())
) {
return Type::combineUnionTypes(Type::getFloat(), Type::getInt());
}
}
2016-10-22 19:23:18 +02:00
if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) {
if (strtolower($stmt->name->parts[0]) === 'false') {
return Type::getFalse();
} elseif (strtolower($stmt->name->parts[0]) === 'true') {
return Type::getBool();
} elseif (strtolower($stmt->name->parts[0]) === 'null') {
return Type::getNull();
}
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
return null;
}
if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) {
if ($stmt->class instanceof PhpParser\Node\Name
&& $stmt->class->parts !== ['static']
&& is_string($stmt->name)
&& isset($existing_class_constants[$stmt->name])
) {
return $existing_class_constants[$stmt->name];
}
return null;
}
if ($stmt instanceof PhpParser\Node\Scalar\String_) {
2016-10-22 19:23:18 +02:00
return Type::getString();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Scalar\LNumber) {
2016-10-22 19:23:18 +02:00
return Type::getInt();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Scalar\DNumber) {
2016-10-22 19:23:18 +02:00
return Type::getFloat();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Array_) {
if (count($stmt->items) === 0) {
return Type::getEmptyArray();
}
2016-10-22 19:23:18 +02:00
return Type::getArray();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\Int_) {
2016-10-22 19:23:18 +02:00
return Type::getInt();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\Double) {
2016-10-22 19:23:18 +02:00
return Type::getFloat();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\Bool_) {
2016-10-22 19:23:18 +02:00
return Type::getBool();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\String_) {
2016-10-22 19:23:18 +02:00
return Type::getString();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) {
2016-10-22 19:23:18 +02:00
return Type::getObject();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) {
2016-10-22 19:23:18 +02:00
return Type::getArray();
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
}
if ($stmt instanceof PhpParser\Node\Expr\UnaryMinus || $stmt instanceof PhpParser\Node\Expr\UnaryPlus) {
return self::getSimpleType($stmt->expr, $statements_source, $existing_class_constants);
2016-06-28 21:28:05 +02:00
}
2016-10-30 17:46:18 +01:00
return null;
2016-10-22 19:23:18 +02:00
}
2016-10-22 19:23:18 +02:00
/**
2016-11-02 07:29:00 +01:00
* @param PhpParser\Node\Stmt\Do_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return false|null
2016-10-22 19:23:18 +02:00
*/
private function analyzeDo(PhpParser\Node\Stmt\Do_ $stmt, Context $context)
2016-10-22 19:23:18 +02:00
{
2017-02-18 23:49:34 +01:00
$do_context = clone $context;
$this->analyzeLoop($stmt->stmts, [], $do_context, $context);
2017-02-18 23:49:34 +01:00
foreach ($context->vars_in_scope as $var => $type) {
if ($type->isMixed()) {
continue;
}
if ($do_context->hasVariable($var)) {
if ($do_context->vars_in_scope[$var]->isMixed()) {
$context->vars_in_scope[$var] = $do_context->vars_in_scope[$var];
}
if ((string)$do_context->vars_in_scope[$var] !== (string)$type) {
$context->vars_in_scope[$var] = Type::combineUnionTypes($do_context->vars_in_scope[$var], $type);
}
}
}
2017-03-13 23:06:56 +01:00
foreach ($do_context->vars_in_scope as $var_id => $type) {
if (!isset($context->vars_in_scope[$var_id])) {
$context->vars_in_scope[$var_id] = $type;
}
}
2017-02-21 23:48:12 +01:00
$context->vars_possibly_in_scope = array_merge(
$context->vars_possibly_in_scope,
$do_context->vars_possibly_in_scope
);
if ($context->collect_references) {
$context->referenced_vars = array_merge(
$context->referenced_vars,
$do_context->referenced_vars
);
}
return ExpressionChecker::analyze($this, $stmt->cond, $context);
}
2016-11-02 07:29:00 +01:00
/**
* @param PhpParser\Node\Stmt\Const_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return void
*/
private function analyzeConstAssignment(PhpParser\Node\Stmt\Const_ $stmt, Context $context)
2016-10-22 19:23:18 +02:00
{
foreach ($stmt->consts as $const) {
ExpressionChecker::analyze($this, $const->value, $context);
2016-10-19 03:54:08 +02:00
2016-11-02 07:29:00 +01:00
$this->setConstType(
$const->name,
isset($const->value->inferredType) ? $const->value->inferredType : Type::getMixed(),
$context
2016-11-02 07:29:00 +01:00
);
2016-08-11 23:36:22 +02:00
}
2016-10-22 19:23:18 +02:00
}
2016-08-11 23:36:22 +02:00
2016-11-02 07:29:00 +01:00
/**
* @param string $const_name
2016-11-21 03:49:06 +01:00
* @param bool $is_fully_qualified
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-05 02:14:04 +01:00
* @return Type\Union|null
2016-11-02 07:29:00 +01:00
*/
public function getConstType(
StatementsChecker $statements_checker,
$const_name,
$is_fully_qualified,
Context $context
) {
2016-11-21 03:49:06 +01:00
$fq_const_name = null;
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$aliased_constants = $this->getAliases()->constants;
2017-01-07 20:35:07 +01:00
if (isset($aliased_constants[$const_name])) {
$fq_const_name = $aliased_constants[$const_name];
} elseif ($is_fully_qualified) {
2016-11-21 03:49:06 +01:00
$fq_const_name = $const_name;
2017-01-07 20:35:07 +01:00
} elseif (strpos($const_name, '\\')) {
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$fq_const_name = ClassLikeChecker::getFQCLNFromString($const_name, $this->getAliases());
2016-11-21 03:49:06 +01:00
}
if ($fq_const_name) {
$const_name_parts = explode('\\', $fq_const_name);
$const_name = array_pop($const_name_parts);
$namespace_name = implode('\\', $const_name_parts);
2017-01-07 20:35:07 +01:00
$namespace_constants = NamespaceChecker::getConstantsForNamespace(
$namespace_name,
\ReflectionProperty::IS_PUBLIC
);
2016-11-21 03:49:06 +01:00
if (isset($namespace_constants[$const_name])) {
return $namespace_constants[$const_name];
}
}
if ($context->hasVariable($const_name)) {
return $context->vars_in_scope[$const_name];
2016-11-21 03:49:06 +01:00
}
$file_path = $statements_checker->getFilePath();
$file_storage_provider = $statements_checker->getFileChecker()->project_checker->file_storage_provider;
$file_storage = $file_storage_provider->get($file_path);
if (isset($file_storage->declaring_constants[$const_name])) {
$constant_file_path = $file_storage->declaring_constants[$const_name];
return $file_storage_provider->get($constant_file_path)->constants[$const_name];
}
2016-11-21 03:49:06 +01:00
$predefined_constants = Config::getInstance()->getPredefinedConstants();
2016-11-21 04:40:19 +01:00
if (isset($predefined_constants[$fq_const_name ?: $const_name])) {
return ClassLikeChecker::getTypeFromValue($predefined_constants[$fq_const_name ?: $const_name]);
2016-11-21 03:49:06 +01:00
}
2017-07-27 01:54:22 +02:00
if (isset(self::$stub_constants[$fq_const_name ?: $const_name])) {
return self::$stub_constants[$fq_const_name ?: $const_name];
}
2016-11-21 03:49:06 +01:00
return null;
2016-10-22 19:23:18 +02:00
}
2016-11-02 07:29:00 +01:00
/**
* @param string $const_name
* @param Type\Union $const_type
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return void
*/
public function setConstType($const_name, Type\Union $const_type, Context $context)
2016-10-22 19:23:18 +02:00
{
$context->vars_in_scope[$const_name] = $const_type;
$context->constants[$const_name] = $const_type;
2016-11-21 03:49:06 +01:00
if ($this->source instanceof NamespaceChecker) {
$this->source->setConstType($const_name, $const_type);
}
}
/**
2016-10-22 19:23:18 +02:00
* @param PhpParser\Node\Stmt\Return_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
* @return false|null
*/
private function analyzeReturn(
ProjectChecker $project_checker,
PhpParser\Node\Stmt\Return_ $stmt,
Context $context
) {
2017-03-02 04:27:52 +01:00
$doc_comment_text = (string)$stmt->getDocComment();
$var_comment = null;
2017-03-02 04:27:52 +01:00
if ($doc_comment_text) {
$var_comment = CommentChecker::getTypeFromComment(
2017-03-02 04:27:52 +01:00
$doc_comment_text,
$context,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$this->source,
$this->source->getAliases()
2017-03-02 04:27:52 +01:00
);
if ($var_comment && $var_comment->var_id) {
$comment_type = ExpressionChecker::fleshOutType(
$project_checker,
Type::parseString($var_comment->type),
$context->self
);
$context->vars_in_scope[$var_comment->var_id] = $comment_type;
}
2017-03-02 04:27:52 +01:00
}
2016-10-22 19:23:18 +02:00
if ($stmt->expr) {
if (ExpressionChecker::analyze($this, $stmt->expr, $context) === false) {
2016-10-22 19:23:18 +02:00
return false;
}
if ($var_comment && !$var_comment->var_id) {
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$stmt->inferredType = Type::parseString($var_comment->type);
2016-11-02 07:29:00 +01:00
} elseif (isset($stmt->expr->inferredType)) {
2016-10-22 19:23:18 +02:00
$stmt->inferredType = $stmt->expr->inferredType;
2016-11-02 07:29:00 +01:00
} else {
2016-10-22 19:23:18 +02:00
$stmt->inferredType = Type::getMixed();
}
2016-11-02 07:29:00 +01:00
} else {
2016-10-22 19:23:18 +02:00
$stmt->inferredType = Type::getVoid();
}
2016-10-22 19:23:18 +02:00
if ($this->source instanceof FunctionLikeChecker) {
$this->source->addReturnTypes($stmt->expr ? (string) $stmt->inferredType : '', $context);
}
2016-11-02 07:29:00 +01:00
return null;
2016-10-22 19:23:18 +02:00
}
2016-11-02 07:29:00 +01:00
/**
* @param PhpParser\Node\Stmt\Throw_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return false|null
*/
private function analyzeThrow(PhpParser\Node\Stmt\Throw_ $stmt, Context $context)
2016-10-22 19:23:18 +02:00
{
return ExpressionChecker::analyze($this, $stmt->expr, $context);
2016-10-22 19:23:18 +02:00
}
/**
* @param string $var_name
2017-05-27 02:16:18 +02:00
*
* @return bool
*/
public function hasVariable($var_name)
{
return isset($this->all_vars[$var_name]);
}
/**
* @param string $var_name
* @param CodeLocation $location
2017-05-27 02:16:18 +02:00
*
* @return void
*/
public function registerVariable($var_name, CodeLocation $location)
{
$this->all_vars[$var_name] = $location;
}
/**
* @param PhpParser\Node\Expr\Include_ $stmt
* @param Context $context
2017-05-27 02:16:18 +02:00
*
* @return false|null
*/
public function analyzeInclude(PhpParser\Node\Expr\Include_ $stmt, Context $context)
2016-07-25 21:05:58 +02:00
{
$config = Config::getInstance();
if (!$config->allow_includes) {
throw new FileIncludeException(
'File includes are not allowed per your Psalm config - check the allowFileIncludes flag.'
);
}
if (ExpressionChecker::analyze($this, $stmt->expr, $context) === false) {
2016-07-25 21:05:58 +02:00
return false;
}
$path_to_file = null;
if ($stmt->expr instanceof PhpParser\Node\Scalar\String_) {
$path_to_file = $stmt->expr->value;
// attempts to resolve using get_include_path dirs
2017-01-07 20:35:07 +01:00
$include_path = self::resolveIncludePath($path_to_file, dirname($this->getCheckedFileName()));
2016-07-25 21:05:58 +02:00
$path_to_file = $include_path ? $include_path : $path_to_file;
2017-01-18 04:10:21 +01:00
if ($path_to_file[0] !== DIRECTORY_SEPARATOR) {
$path_to_file = getcwd() . DIRECTORY_SEPARATOR . $path_to_file;
2016-07-25 21:05:58 +02:00
}
2016-11-02 07:29:00 +01:00
} else {
$path_to_file = self::getPathTo($stmt->expr, $this->getCheckedFileName());
2016-07-25 21:05:58 +02:00
}
if ($path_to_file) {
$reduce_pattern = '/\/[^\/]+\/\.\.\//';
while (preg_match($reduce_pattern, $path_to_file)) {
2017-01-18 04:10:21 +01:00
$path_to_file = preg_replace($reduce_pattern, DIRECTORY_SEPARATOR, $path_to_file);
2016-07-25 21:05:58 +02:00
}
// if the file is already included, we can't check much more
2017-05-27 02:05:57 +02:00
if (in_array($path_to_file, get_included_files(), true)) {
2016-11-02 07:29:00 +01:00
return null;
2016-07-25 21:05:58 +02:00
}
if ($this->getFilePath() === $path_to_file) {
return null;
}
2017-01-08 01:07:58 +01:00
$current_file_checker = $this->getFileChecker();
2017-07-27 01:36:41 +02:00
if ($current_file_checker->project_checker->fileExists($path_to_file)) {
if (is_subclass_of($current_file_checker, 'Psalm\\Checker\\FileChecker')) {
$include_file_checker = new FileChecker(
$path_to_file,
$current_file_checker->project_checker,
false
);
$this->analyze($include_file_checker->getStatements(), $context);
}
2016-11-02 07:29:00 +01:00
return null;
2016-07-25 21:05:58 +02:00
}
if (IssueBuffer::accepts(
2017-10-29 22:36:02 +01:00
new MissingFile(
'Cannot find file ' . $path_to_file . ' to include',
new CodeLocation($this->source, $stmt)
),
$this->source->getSuppressedIssues()
)) {
// fall through
}
} else {
if (IssueBuffer::accepts(
new UnresolvableInclude(
'Cannot resolve the given expression to a file path',
new CodeLocation($this->source, $stmt)
),
$this->source->getSuppressedIssues()
)) {
// fall through
}
2016-07-25 21:05:58 +02:00
}
$context->check_classes = false;
$context->check_variables = false;
$context->check_functions = false;
2017-05-25 04:07:49 +02:00
2016-11-02 07:29:00 +01:00
return null;
2016-07-25 21:05:58 +02:00
}
/**
* @param PhpParser\Node\Expr $stmt
* @param string $file_name
2017-05-27 02:16:18 +02:00
*
* @return string|null
2016-12-17 06:48:31 +01:00
* @psalm-suppress MixedAssignment
*/
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
public static function getPathTo(PhpParser\Node\Expr $stmt, $file_name)
2016-03-23 18:05:25 +01:00
{
2017-01-18 04:10:21 +01:00
if ($file_name[0] !== DIRECTORY_SEPARATOR) {
$file_name = getcwd() . DIRECTORY_SEPARATOR . $file_name;
2016-03-23 18:05:25 +01:00
}
if ($stmt instanceof PhpParser\Node\Scalar\String_) {
return $stmt->value;
} elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) {
2016-08-11 00:10:12 +02:00
$left_string = self::getPathTo($stmt->left, $file_name);
$right_string = self::getPathTo($stmt->right, $file_name);
2016-03-23 18:05:25 +01:00
if ($left_string && $right_string) {
return $left_string . $right_string;
}
} elseif ($stmt instanceof PhpParser\Node\Expr\FuncCall &&
$stmt->name instanceof PhpParser\Node\Name &&
2016-11-02 07:29:00 +01:00
$stmt->name->parts === ['dirname']
) {
2016-03-23 18:05:25 +01:00
if ($stmt->args) {
2016-08-11 00:10:12 +02:00
$evaled_path = self::getPathTo($stmt->args[0]->value, $file_name);
2016-03-23 18:05:25 +01:00
if (!$evaled_path) {
2016-11-02 07:29:00 +01:00
return null;
2016-03-23 18:05:25 +01:00
}
return dirname($evaled_path);
}
} elseif ($stmt instanceof PhpParser\Node\Expr\ConstFetch && $stmt->name instanceof PhpParser\Node\Name) {
$const_name = implode('', $stmt->name->parts);
if (defined($const_name)) {
$constant_value = constant($const_name);
if (is_string($constant_value)) {
return $constant_value;
}
2016-03-23 18:05:25 +01:00
}
} elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\Dir) {
return dirname($file_name);
} elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst\File) {
return $file_name;
}
return null;
}
2016-11-02 07:29:00 +01:00
/**
* @param string $file_name
* @param string $current_directory
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return string|null
*/
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
public static function resolveIncludePath($file_name, $current_directory)
2016-03-23 18:05:25 +01:00
{
2017-01-08 01:07:58 +01:00
if (!$current_directory) {
return $file_name;
}
2016-11-02 07:29:00 +01:00
$paths = PATH_SEPARATOR == ':'
? preg_split('#(?<!phar):#', get_include_path())
: explode(PATH_SEPARATOR, get_include_path());
2016-03-23 18:05:25 +01:00
foreach ($paths as $prefix) {
$ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
if ($prefix === '.') {
$prefix = $current_directory;
}
$file = $prefix . $ds . $file_name;
if (file_exists($file)) {
return $file;
}
}
2016-11-02 07:29:00 +01:00
return null;
2016-03-23 18:05:25 +01:00
}
2016-10-22 19:23:18 +02:00
/**
* The first appearance of the variable in this set of statements being evaluated
2016-11-02 07:29:00 +01:00
*
2016-10-22 19:23:18 +02:00
* @param string $var_name
2017-05-27 02:16:18 +02:00
*
* @return CodeLocation|null
2016-10-22 19:23:18 +02:00
*/
public function getFirstAppearance($var_name)
2016-10-02 19:05:49 +02:00
{
2016-10-22 19:23:18 +02:00
return isset($this->all_vars[$var_name]) ? $this->all_vars[$var_name] : null;
2016-10-02 19:05:49 +02:00
}
2016-10-21 00:16:17 +02:00
public function getFileChecker()
{
return $this->file_checker;
}
/**
* @return array<string, FunctionChecker>
*/
public function getFunctionCheckers()
{
return $this->function_checkers;
}
2016-11-02 07:29:00 +01:00
/**
* @return void
*/
2016-10-21 00:16:17 +02:00
public static function clearCache()
{
2017-07-27 01:54:22 +02:00
self::$stub_constants = [];
2016-10-22 23:35:59 +02:00
ExpressionChecker::clearCache();
2016-10-21 00:16:17 +02:00
}
}