Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance offset access by defining various access modes, and restrict which ones are available for DOM classes #3724

Draft
wants to merge 2 commits into
base: 2.0.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\VerbosityLevel;
Expand Down Expand Up @@ -62,10 +63,20 @@ public function processNode(Node $node, Scope $scope): array
$isOffsetAccessible = $isOffsetAccessibleType->isOffsetAccessible();

if ($scope->isInExpressionAssign($node) && $isOffsetAccessible->yes()) {
return [];
if ($isOffsetAccessibleType->isOffsetAccessLegal(AccessOffsetMode::Write)->yes()) {
return [];
} else {
// TODO Improve
return [
RuleErrorBuilder::message(sprintf(
'Cannot access an offset on %s.',
$isOffsetAccessibleType->describe(VerbosityLevel::typeOnly()),
))->identifier('offsetAccess.nonOffsetAccessible')->build(),
];
}
}

if ($scope->isUndefinedExpressionAllowed($node) && $isOffsetAccessibleType->isOffsetAccessLegal()->yes()) {
if ($scope->isUndefinedExpressionAllowed($node) && $isOffsetAccessibleType->isOffsetAccessLegal(AccessOffsetMode::Read)->yes()) {
return [];
}

Expand Down
15 changes: 15 additions & 0 deletions src/Type/AccessOffsetMode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace PHPStan\Type;

enum AccessOffsetMode
{
case Exist;
case Read;
case Write;
case ReadWrite;
case Unset;
case Append;
case IncrementDecrement;
case Fetch; // By reference fetch
}
3 changes: 2 additions & 1 deletion src/Type/Accessory/AccessoryArrayListType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantFloatType;
Expand Down Expand Up @@ -130,7 +131,7 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createYes();
}
Expand Down
8 changes: 3 additions & 5 deletions src/Type/Accessory/AccessoryLiteralStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -27,6 +28,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
Expand All @@ -42,6 +44,7 @@ class AccessoryLiteralStringType implements CompoundType, AccessoryType
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -123,11 +126,6 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
8 changes: 3 additions & 5 deletions src/Type/Accessory/AccessoryLowercaseStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -26,6 +27,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
Expand All @@ -41,6 +43,7 @@ class AccessoryLowercaseStringType implements CompoundType, AccessoryType
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -119,11 +122,6 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
8 changes: 3 additions & 5 deletions src/Type/Accessory/AccessoryNonEmptyStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -26,6 +27,7 @@
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
Expand All @@ -43,6 +45,7 @@ class AccessoryNonEmptyStringType implements CompoundType, AccessoryType
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use UndecidedBooleanTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -125,11 +128,6 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
9 changes: 3 additions & 6 deletions src/Type/Accessory/AccessoryNonFalsyStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -26,6 +27,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\TruthyBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
Expand All @@ -43,6 +45,7 @@ class AccessoryNonFalsyStringType implements CompoundType, AccessoryType
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -124,12 +127,6 @@ public function isOffsetAccessible(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
8 changes: 3 additions & 5 deletions src/Type/Accessory/AccessoryNumericStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -25,6 +26,7 @@
use PHPStan\Type\Traits\NonGenericTypeTrait;
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
Expand All @@ -42,6 +44,7 @@ class AccessoryNumericStringType implements CompoundType, AccessoryType
use UndecidedBooleanTypeTrait;
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -128,11 +131,6 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
8 changes: 3 additions & 5 deletions src/Type/Accessory/AccessoryUppercaseStringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
Expand All @@ -26,6 +27,7 @@
use PHPStan\Type\Traits\NonIterableTypeTrait;
use PHPStan\Type\Traits\NonObjectTypeTrait;
use PHPStan\Type\Traits\NonRemoveableTypeTrait;
use PHPStan\Type\Traits\StringTypeTrait;
use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
Expand All @@ -41,6 +43,7 @@ class AccessoryUppercaseStringType implements CompoundType, AccessoryType
use UndecidedComparisonCompoundTypeTrait;
use NonGenericTypeTrait;
use NonRemoveableTypeTrait;
use StringTypeTrait;

/** @api */
public function __construct()
Expand Down Expand Up @@ -119,11 +122,6 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasOffsetValueType(Type $offsetType): TrinaryLogic
{
return $offsetType->isInteger()->and(TrinaryLogic::createMaybe());
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/HasMethodType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\CompoundType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\IntersectionType;
Expand Down Expand Up @@ -111,7 +112,7 @@ public function describe(VerbosityLevel $level): string
return sprintf('hasMethod(%s)', $this->methodName);
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/HasOffsetType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantIntegerType;
Expand Down Expand Up @@ -130,7 +131,7 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createYes();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/HasOffsetValueType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\ShouldNotHappenException;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantIntegerType;
Expand Down Expand Up @@ -142,7 +143,7 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createYes();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/HasPropertyType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Reflection\TrivialParametersAcceptor;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\CompoundType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\IntersectionType;
Expand Down Expand Up @@ -106,7 +107,7 @@ public function describe(VerbosityLevel $level): string
return sprintf('hasProperty(%s)', $this->propertyName);
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createMaybe();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/NonEmptyArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantFloatType;
Expand Down Expand Up @@ -128,7 +129,7 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createYes();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/Accessory/OversizedArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\TrinaryLogic;
use PHPStan\Type\AcceptsResult;
use PHPStan\Type\AccessOffsetMode;
use PHPStan\Type\BooleanType;
use PHPStan\Type\CompoundType;
use PHPStan\Type\Constant\ConstantFloatType;
Expand Down Expand Up @@ -124,7 +125,7 @@ public function isOffsetAccessible(): TrinaryLogic
return TrinaryLogic::createYes();
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
return TrinaryLogic::createYes();
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/BooleanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ public function toArrayKey(): Type
return new UnionType([new ConstantIntegerType(0), new ConstantIntegerType(1)]);
}

public function isOffsetAccessLegal(): TrinaryLogic
public function isOffsetAccessLegal(AccessOffsetMode $mode): TrinaryLogic
{
// TODO Should this be NO?
return TrinaryLogic::createYes();
}

Expand Down
Loading
Loading