Skip to content

Commit

Permalink
Introduce Virtual Nodes in order to differentiate real nodes in plugi…
Browse files Browse the repository at this point in the history
…ns (#5222)
  • Loading branch information
orklah committed Feb 15, 2021
1 parent 77feecb commit 5191dac
Show file tree
Hide file tree
Showing 194 changed files with 2,192 additions and 217 deletions.
6 changes: 4 additions & 2 deletions examples/TemplateChecker.php
Expand Up @@ -11,6 +11,8 @@
use Psalm\CodeLocation;
use Psalm\Context;
use Psalm\DocComment;
use Psalm\Node\Stmt\VirtualClass;
use Psalm\Node\Stmt\VirtualClassMethod;
use Psalm\Storage\MethodStorage;
use Psalm\Type;

Expand Down Expand Up @@ -147,9 +149,9 @@ protected function checkWithViewClass(Context $context, array $stmts): void

$pseudo_method_name = preg_replace('/[^a-zA-Z0-9_]+/', '_', $this->file_name);

$class_method = new PhpParser\Node\Stmt\ClassMethod($pseudo_method_name, ['stmts' => []]);
$class_method = new VirtualClassMethod($pseudo_method_name, ['stmts' => []]);

$class = new PhpParser\Node\Stmt\Class_(self::VIEW_CLASS);
$class = new VirtualClass(self::VIEW_CLASS);

$class_analyzer = new ClassAnalyzer($class, $this, self::VIEW_CLASS);

Expand Down
19 changes: 19 additions & 0 deletions psalm.xml.dist
Expand Up @@ -73,6 +73,7 @@
<errorLevel type="suppress">
<directory name="examples"/>
<directory name="src/Psalm/Internal/Fork" />
<directory name="src/Psalm/Node" />
<file name="src/Psalm/Plugin/Shepherd.php" />
<file name="src/Psalm/Plugin/Hook/MethodReturnTypeProviderInterface.php"/>
</errorLevel>
Expand Down Expand Up @@ -131,5 +132,23 @@
<directory name="tests"/>
</errorLevel>
</PossiblyUndefinedStringArrayOffset>

<MixedPropertyTypeCoercion>
<errorLevel type="suppress">
<directory name="vendor/nikic/php-parser" />
</errorLevel>
</MixedPropertyTypeCoercion>

<PropertyTypeCoercion>
<errorLevel type="suppress">
<directory name="vendor/nikic/php-parser" />
</errorLevel>
</PropertyTypeCoercion>

<MixedAssignment>
<errorLevel type="suppress">
<directory name="vendor/nikic/php-parser" />
</errorLevel>
</MixedAssignment>
</issueHandlers>
</psalm>
15 changes: 9 additions & 6 deletions src/Psalm/Internal/Algebra/FormulaGenerator.php
Expand Up @@ -7,6 +7,9 @@
use Psalm\Internal\Algebra;
use Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder;
use Psalm\Internal\Clause;
use Psalm\Node\Expr\BinaryOp\VirtualBooleanAnd;
use Psalm\Node\Expr\BinaryOp\VirtualBooleanOr;
use Psalm\Node\Expr\VirtualBooleanNot;
use function array_merge;
use function count;
use function strlen;
Expand Down Expand Up @@ -88,12 +91,12 @@ public static function getFormula(

if ($conditional instanceof PhpParser\Node\Expr\BooleanNot) {
if ($conditional->expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
$and_expr = new PhpParser\Node\Expr\BinaryOp\BooleanAnd(
new PhpParser\Node\Expr\BooleanNot(
$and_expr = new VirtualBooleanAnd(
new VirtualBooleanNot(
$conditional->expr->left,
$conditional->getAttributes()
),
new PhpParser\Node\Expr\BooleanNot(
new VirtualBooleanNot(
$conditional->expr->right,
$conditional->getAttributes()
),
Expand Down Expand Up @@ -170,12 +173,12 @@ public static function getFormula(
}

if ($conditional->expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
$and_expr = new PhpParser\Node\Expr\BinaryOp\BooleanOr(
new PhpParser\Node\Expr\BooleanNot(
$and_expr = new VirtualBooleanOr(
new VirtualBooleanNot(
$conditional->expr->left,
$conditional->getAttributes()
),
new PhpParser\Node\Expr\BooleanNot(
new VirtualBooleanNot(
$conditional->expr->right,
$conditional->getAttributes()
),
Expand Down
15 changes: 10 additions & 5 deletions src/Psalm/Internal/Analyzer/AttributeAnalyzer.php
Expand Up @@ -2,6 +2,11 @@
namespace Psalm\Internal\Analyzer;

use PhpParser;
use Psalm\Node\Expr\VirtualNew;
use Psalm\Node\Name\VirtualFullyQualified;
use Psalm\Node\Stmt\VirtualExpression;
use Psalm\Node\VirtualArg;
use Psalm\Node\VirtualIdentifier;
use Psalm\Storage\AttributeStorage;
use Psalm\Storage\ClassLikeStorage;
use Psalm\Internal\Scanner\UnresolvedConstantComponent;
Expand Down Expand Up @@ -123,22 +128,22 @@ public static function analyze(

$type_expr->setAttributes($arg_attributes);

$node_args[] = new PhpParser\Node\Arg(
$node_args[] = new VirtualArg(
$type_expr,
false,
false,
$arg_attributes,
$storage_arg->name
? new PhpParser\Node\Identifier(
? new VirtualIdentifier(
$storage_arg->name,
$arg_attributes
)
: null
);
}

$new_stmt = new PhpParser\Node\Expr\New_(
new PhpParser\Node\Name\FullyQualified(
$new_stmt = new VirtualNew(
new VirtualFullyQualified(
$attribute->fq_class_name,
[
'startFilePos' => $attribute->name_location->raw_file_start,
Expand All @@ -160,7 +165,7 @@ public static function analyze(
);

$statements_analyzer->analyze(
[new PhpParser\Node\Stmt\Expression($new_stmt)],
[new VirtualExpression($new_stmt)],
new \Psalm\Context()
);
}
Expand Down
24 changes: 16 additions & 8 deletions src/Psalm/Internal/Analyzer/ClassAnalyzer.php
Expand Up @@ -43,6 +43,14 @@
use Psalm\Issue\UnimplementedAbstractMethod;
use Psalm\Issue\UnimplementedInterfaceMethod;
use Psalm\IssueBuffer;
use Psalm\Node\Expr\VirtualStaticCall;
use Psalm\Node\Expr\VirtualVariable;
use Psalm\Node\Name\VirtualFullyQualified;
use Psalm\Node\Stmt\VirtualClassMethod;
use Psalm\Node\Stmt\VirtualExpression;
use Psalm\Node\VirtualArg;
use Psalm\Node\VirtualIdentifier;
use Psalm\Node\VirtualParam;
use Psalm\Plugin\EventHandler\Event\AfterClassLikeAnalysisEvent;
use Psalm\StatementsSource;
use Psalm\Storage\ClassLikeStorage;
Expand Down Expand Up @@ -1042,8 +1050,8 @@ function (FunctionLikeParameter $param) : PhpParser\Node\Arg {
]
: [];

return new PhpParser\Node\Arg(
new PhpParser\Node\Expr\Variable($param->name, $attributes),
return new VirtualArg(
new VirtualVariable($param->name, $attributes),
false,
$param->is_variadic,
$attributes
Expand All @@ -1068,19 +1076,19 @@ function (FunctionLikeParameter $param) : PhpParser\Node\Arg {
];

$fake_constructor_stmts = [
new PhpParser\Node\Stmt\Expression(
new PhpParser\Node\Expr\StaticCall(
new PhpParser\Node\Name\FullyQualified($constructor_declaring_fqcln),
new PhpParser\Node\Identifier('__construct', $fake_constructor_attributes),
new VirtualExpression(
new VirtualStaticCall(
new VirtualFullyQualified($constructor_declaring_fqcln),
new VirtualIdentifier('__construct', $fake_constructor_attributes),
$fake_constructor_stmt_args,
$fake_call_attributes
),
$fake_call_attributes
),
];

$fake_stmt = new PhpParser\Node\Stmt\ClassMethod(
new PhpParser\Node\Identifier('__construct'),
$fake_stmt = new VirtualClassMethod(
new VirtualIdentifier('__construct'),
[
'type' => PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC,
'params' => $fake_constructor_params,
Expand Down
10 changes: 6 additions & 4 deletions src/Psalm/Internal/Analyzer/Statements/Block/ForeachAnalyzer.php
Expand Up @@ -28,6 +28,8 @@
use Psalm\Issue\UnnecessaryVarAnnotation;
use Psalm\IssueBuffer;
use Psalm\Internal\Scope\LoopScope;
use Psalm\Node\Expr\VirtualMethodCall;
use Psalm\Node\VirtualIdentifier;
use Psalm\Type;
use function is_string;
use function in_array;
Expand Down Expand Up @@ -777,9 +779,9 @@ public static function handleIterable(

$statements_analyzer->node_data = clone $statements_analyzer->node_data;

$fake_method_call = new PhpParser\Node\Expr\MethodCall(
$fake_method_call = new VirtualMethodCall(
$foreach_expr,
new PhpParser\Node\Identifier('getIterator', $foreach_expr->getAttributes())
new VirtualIdentifier('getIterator', $foreach_expr->getAttributes())
);

$suppressed_issues = $statements_analyzer->getSuppressedIssues();
Expand Down Expand Up @@ -1061,9 +1063,9 @@ private static function getFakeMethodCallType(

$statements_analyzer->node_data = clone $statements_analyzer->node_data;

$fake_method_call = new PhpParser\Node\Expr\MethodCall(
$fake_method_call = new VirtualMethodCall(
$foreach_expr,
new PhpParser\Node\Identifier($method_name, $foreach_expr->getAttributes())
new VirtualIdentifier($method_name, $foreach_expr->getAttributes())
);

$suppressed_issues = $statements_analyzer->getSuppressedIssues();
Expand Down
15 changes: 10 additions & 5 deletions src/Psalm/Internal/Analyzer/Statements/Block/IfElse/IfAnalyzer.php
Expand Up @@ -13,6 +13,11 @@
use Psalm\IssueBuffer;
use Psalm\Internal\Scope\IfScope;
use Psalm\Internal\Scope\IfConditionalScope;
use Psalm\Node\Expr\BinaryOp\VirtualBooleanOr;
use Psalm\Node\Expr\VirtualBooleanNot;
use Psalm\Node\Expr\VirtualFuncCall;
use Psalm\Node\Name\VirtualFullyQualified;
use Psalm\Node\VirtualArg;
use Psalm\Type;
use Psalm\Internal\Algebra;
use Psalm\Type\Reconciler;
Expand Down Expand Up @@ -356,7 +361,7 @@ public static function addConditionallyAssignedVarsToContext(

foreach ($exprs as $expr) {
if ($expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
$fake_not = new PhpParser\Node\Expr\BinaryOp\BooleanOr(
$fake_not = new VirtualBooleanOr(
self::negateExpr($expr->left),
self::negateExpr($expr->right),
$expr->getAttributes()
Expand All @@ -365,9 +370,9 @@ public static function addConditionallyAssignedVarsToContext(
$fake_not = self::negateExpr($expr);
}

$fake_negated_expr = new PhpParser\Node\Expr\FuncCall(
new PhpParser\Node\Name\FullyQualified('assert'),
[new PhpParser\Node\Arg(
$fake_negated_expr = new VirtualFuncCall(
new VirtualFullyQualified('assert'),
[new VirtualArg(
$fake_not,
false,
false,
Expand Down Expand Up @@ -424,7 +429,7 @@ private static function negateExpr(PhpParser\Node\Expr $expr) : PhpParser\Node\E
return $expr->expr;
}

return new PhpParser\Node\Expr\BooleanNot($expr, $expr->getAttributes());
return new VirtualBooleanNot($expr, $expr->getAttributes());
}

/**
Expand Down
Expand Up @@ -10,6 +10,7 @@
use Psalm\CodeLocation;
use Psalm\Context;
use Psalm\Internal\Scope\IfScope;
use Psalm\Node\Expr\VirtualBooleanNot;
use Psalm\Type;
use Psalm\Internal\Algebra;
use Psalm\Type\Reconciler;
Expand Down Expand Up @@ -204,7 +205,7 @@ function ($c) use ($reconciled_expression_clauses): bool {
$if_scope->negated_clauses = FormulaGenerator::getFormula(
$cond_object_id,
$cond_object_id,
new PhpParser\Node\Expr\BooleanNot($stmt->cond),
new VirtualBooleanNot($stmt->cond),
$context->self,
$statements_analyzer,
$codebase,
Expand Down

0 comments on commit 5191dac

Please sign in to comment.