Report new on an expression whose type is not string|object via new.nonObject#5866
Conversation
e237c69 to
57a00e8
Compare
57a00e8 to
d391efd
Compare
d391efd to
9def6e9
Compare
VincentLanglet
left a comment
There was a problem hiding this comment.
This should be behind a flag which is enabled by bleedingEdge
|
Done. I addressed VincentLanglet's review. What I changedThe reviewer asked that the new
One gotcha worth noting: after adding a new Verification
Committed as |
d17ff9d to
02752a0
Compare
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
32ec174 to
f6dc3a6
Compare
|
@VincentLanglet I think this one is good to go |
Should we consider this as a new rule which need to be check by ondrej ? |
|
I don't think so. its a new error-case within a pre-existing rule (and its even in bleeding edge only). |
Summary
PHPStan did not detect when the
newoperator is used with an expression whose type can never be a valid class name. For examplenew $classwhere$classisintwas silently accepted, even though it always fails at runtime. This PR makesInstantiationRulereport such cases with a newnew.nonObjecterror, mirroring the existing checks for the analogous dynamic-class-name constructs.Changes
src/Rules/Classes/InstantiationRule.phpRuleLevelHelperand addedcheckClassNameExprType(), run fornew $expr(when the class is an expression).findTypeToCheck()against the accepted typestring|object(new UnionType([new StringType(), new ObjectWithoutClassType()])) and reportsCannot instantiate class using <type>.with identifiernew.nonObjectwhen the type is not a supertype-compatiblestring/object.ErrorTyperesults (mixed/never/unknown class) are intentionally skipped so the existingclass.notFound("Instantiated class X not found.") path keeps working for object values of unknown classes.src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.phpbase64_decode()when the input is a constant string, returning the decodedConstantStringType(orfalsein strict mode for invalid base64). The decode always runs in strict mode internally; for a non-strict call on invalid input the extension falls back to the genericstringrather than guessing the lenient result.tests/PHPStan/Rules/Classes/data/instantiation-non-object.php+testInstantiationWithNonObjectType()inInstantiationRuleTest.InstantiationRuletest factories (InstantiationRuleTest,ForbiddenNameCheckExtensionRuleTest) for the new constructor argument.tests/PHPStan/Analyser/nsrt/base64_decode.phpwith constant-input cases and adjusted the constant''expectations intests/PHPStan/Analyser/nsrt/functions.php.Root cause
InstantiationRule::getClassNames()only produced class names from constant strings and object types; for any other expression type it returned an empty list, so no error was ever emitted fornew $wrongType. The fix adds an explicit type check for the expression form ofnew, using the samestring|objectacceptance criterion that the parallel rules already use.Parallel-construct audit (dynamic class name in a class-name context): static method call (
staticMethod.nonObject), static property access (staticProperty.nonObject), class constant fetch (classConstant.nonObject) andinstanceof(instanceof.invalidExprType) already report wrong dynamic class types.newwas the single missing member of that family, now covered.The
base64_decode()constant-folding is required because PHPStan's own source instantiates a base64-obfuscated adapter class name (new $enumAdapter(...)inNodeScopeResolverandBetterReflectionProvider). Without folding, that value isstring|false, which the new rule correctly flags. Folding resolves it to the preciseclass-string, which both satisfies the new rule and lets the surroundingClassReflectionFactory::create()call stay well-typed — i.e. teaching inference rather than rewriting the source.Test
InstantiationRuleTest::testInstantiationWithNonObjectType()assertsnew.nonObjectis reported fornew $int,new $float,new $bool,new $intOrStringandnew $array, and that valid forms (string,class-string,object, an instance) produce no error. Verified the data file produces no errors before the rule change.tests/PHPStan/Analyser/nsrt/base64_decode.phpasserts the new constant-folded return types ('Hello world',false,string).make tests: 17383 tests) andmake phpstanshows no new errors (only pre-existingshipmonk.deadMethodfindings unrelated to this change).Fixes phpstan/phpstan#4922