-
-
Notifications
You must be signed in to change notification settings - Fork 370
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
[DX] Make ClassAnnotationMatcher differentiate between known and unknown classes #2319
[DX] Make ClassAnnotationMatcher differentiate between known and unknown classes #2319
Conversation
.../BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher/ResolveTagFullyQualifiedNameTest.php
Outdated
Show resolved
Hide resolved
45fb95a
to
259d044
Compare
@samsonasik Tests are green now. Could you take another look? |
packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php
Outdated
Show resolved
Hide resolved
/** @var \My\Namespace\UnknownClass */ | ||
private $unknownNamespacedClass; | ||
// /** @var OtherUnknownClass */ | ||
// private $unknownUsedClass; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why it is commented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a testcase we currently cannot cover because the OtherUnknownClass
is imported (= used). So, this is a case we cannot detect properly. As far as I know, PHP ignores use statements pointing to non existant classes.
I could have removed this case, but I think it is worth mentioning. I'll write a helpful comment..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about create a test case for direct rector rule usage? eg, for DoctrineTargetEntityStringToClassConstantRector
usage.
I think that will be clearer for the purpose and use case.
You can add the test case to tests/Issues
directory as the rule is from rector-doctrine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the test is now specific for name resolution. I mean, yes, DoctrineTargetEntityStringToClassConstantRector
will benefit from this feature, but other users of ClassAnnotationMatcher->resolveTagFullyQualifiedName()
could benefit as well. So, I suggest to keep this test at a central place (here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure without real failing test case example in a rule, docblock is depends on the statement next to it, so it will be still read by next stmt (as property), possibly by children of VarTagValueNode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. I changed the code to check if the class really exists and added some more tests. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add test for usage in rule, eg: on DoctrineTargetEntityStringToClassConstantRector
?
You can add the test case to tests/Issues directory as the rule is from rector-doctrine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Now I understood what you meant in the first place. Apologies for getting you wrong and thanks for your patience. I added a Testcase under tests/Issues/DoNotReplaceUnknownTargetEntities
. This test fails, because the DoctrineTargetEntityStringToClassConstantRector needs to use ClassAnnotationMatcher->resolveTagToKnownFullyQualifiedName()
now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you make test passed then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the tests reflect the status quo for now, so they pass. IMHO, it would be better to mark them as skipped, but I couldn't figure out how to do that.
I'll create other PRs in rector-doctrine to fix them properly.
19489bc
to
be78bf6
Compare
tests/Issues/DoNotReplaceUnknownTargetEntities/Fixture/unknown_target_entity.php.inc
Outdated
Show resolved
Hide resolved
tests/Issues/DoNotReplaceUnknownTargetEntities/Fixture/unknown_target_entity.php.inc
Outdated
Show resolved
Hide resolved
tests/Issues/DoNotReplaceUnknownTargetEntities/Fixture/unknown_target_entity.php.inc
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok for me 👍
private $unknownAliasedUsedClass; | ||
/** @var \UnknownGlobalClass */ | ||
private $unknownGlobalClass; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you split the test case by shared topic?
It is easier to debug, when one of them breaks.
Feel free to nest those in /Fixture/NonExistingClass
directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why phpstan fails. I get no error, when run locally..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rebased to the latest main and phpstan passes now.
7205dd1
to
80f91f2
Compare
# Conflicts: # packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php
…_target_entity.php.inc Co-authored-by: Abdul Malik Ikhsan <samsonasik@gmail.com>
…_target_entity.php.inc Co-authored-by: Abdul Malik Ikhsan <samsonasik@gmail.com>
Thank you @dritter for extensive work on this 👏 |
Before this change, a call to
ClassAnnotationMatcher->resolveTagFullyQualifiedName()
could not distinguish between a known and unknown class. This is relevant for rules that transform@var
annotations to type hints (@var
annotation may point to an unknown class). InternallyresolveTagFullyQualifiedName()
delegates toUseImportNameMatcher->matchNameWithUses()
, which simply returns the original string if not found. If this happens, the rule cannot tell, if this is a global class, or an unknown one.This PR changes
ClassAnnotationMatcher->resolveTagFullyQualifiedName()
to returnnull
if the class is not known.There is one caveat: If the unknown class was imported anyway, we do not detect this case (see ClassAnnotationMatcher/Fixture/fixture.php.inc#L18-L19). IMHO such a case is better handled in a separate rule..
Background:
I stumbled upon this when working on Add Rule to convert Doctrine String Classes in targetEntity to Class Constant , where a
targetEntity
might point to an unknown (or global) class.