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

Verify method, function, property, constant and interface changes and report BC breaks #38

Merged
merged 111 commits into from
Apr 26, 2018

Conversation

Ocramius
Copy link
Member

@Ocramius Ocramius commented Apr 15, 2018

Fixes #7
Fixes #8
Fixes #9
Fixes #10
Fixes #11
Fixes #12
Fixes #41
Fixes #43
Fixes #46

@Ocramius Ocramius added this to the 0.0.1 milestone Apr 15, 2018
@Ocramius Ocramius self-assigned this Apr 15, 2018
@Ocramius Ocramius changed the title Verify parameter type contravariance and return type covariance in method signature Verify method, function, property, constant and interface changes and report BC breaks Apr 16, 2018
Ocramius added 22 commits April 17, 2018 00:35
…` for `ReflectionClass` (where applicable) to avoid passing around a `Reflector`
…ionClass` for `ReflectionClass` (where applicable) to avoid passing around a `Reflector`"

This reverts commit e07a9ce.
…veraging the BetterReflection `AbstractReflectionFunction` existing API
@@ -31,7 +40,210 @@
new GetVersionCollectionFromGitRepository(),
new PickLastMinorVersionFromCollection(),
new Comparator(
new Comparator\BackwardsCompatibility\ClassBased\PropertyRemoved()
Copy link
Member Author

@Ocramius Ocramius Apr 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this tree of checks is quite huge, but is pretty much describing what kinds of BC breaks we want to rely upon.

If we want to make it more "friendly", I can move the instantiation to Roave\ApiCompare\ApiCompare#defaultClassChecks(), Roave\ApiCompare\ApiCompare#defaultInterfaceChecks(), Roave\ApiCompare\ApiCompare#defaultTraitChecks() in a separate patch.

@Ocramius
Copy link
Member Author

@asgrim this is ready for another round. Renamed few things, introduced traits checks.

@@ -132,7 +129,7 @@ public function execute(InputInterface $input, OutputInterface $output) : int
$outputFormats = $input->getOption('format') ?: [];
Assert::that($outputFormats)->isArray();

if (in_array('markdown', $outputFormats, true)) {
if (ArrayHelpers::stringArrayContainsString('markdown', $outputFormats)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhh, probably a little OTT on the checking here... passing true includes type checks anyway, so the array passed doesn't even need to be all strings, if it matches, it matches, if not, it doesn't...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to avoid colliding with various tools that say different things here:

  • infection
  • ea inspections
  • phpstan strict checks

Segregating it out was easy peasy, so I just did it, and we have a single location where in_array() still exists.

Yes, this is indeed overblown, but I'd be OK with this particular addition, considering that it really is the only thing needed to make mutation tests work without problems (could've been much worse).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another potential issue: contributors (me included) will likely default to just using in_array in future contributions, that may slip through the net :/ it's a non-standard approach, which is "unexpected" and inconsistent with current ... "ways" (for want of a better word)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that may slip through the net

Build will catch it now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the build fail with a message that indicates that ArrayHelpers::stringArrayContainsString should be used instead? (rhetorical question: it doesn't). The point is, you're solving a problem caused by the tooling (because in_array with strict param set to true is fine), and the solution is not what people will expect. I understand the technical reasoning here, and it's perfectly sound logic: my concern is that when you don't know what the issue is, the solution is unexpected and unconventional. I don't have a better answer, apart from this shouldn't be a problem and that the finger points back to the tools (phpstan, in this specific case)... :s

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it won't fail with a matching error message, obviously.

the solution is not what people will expect.

Agreed, but I don't expect that to be a blocker, as a quick review can deal with most of these errors.

the solution is unexpected and unconventional.

Agreed again, as I said, the mutation testing outcome was much better than expected, so I'm quite happy with having this deviation from the standard compared to what it could have been if we had much more mutations.

apart from this shouldn't be a problem and that the finger points back to the tools (phpstan, in this specific case)...

Possible, but I don't think that should become a blocker for just a workaround in here. Assuming that we fix phpstan there, we can really just revert this addition (API is marked @internal anyway) and that's the end of the story :-P

@@ -19,12 +20,17 @@ class Comparator
/** @var InterfaceBased */
private $interfaceBasedComparisons;

/** @var TraitBased */
private $traitBasedComparisons;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wish we'd added traits as a different PR :s this PR is getting way too big, stuff is gonna get missed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - did it mostly due to time constraints on my end, as I was in a hurry/constantly on the road yesterday.

@@ -21,7 +21,8 @@
"phpunit/phpunit": "^7.0",
"doctrine/coding-standard": "^4.0",
"squizlabs/php_codesniffer": "^3.2",
"phpstan/phpstan": "^0.9.2"
"phpstan/phpstan": "^0.9.2",
"infection/infection": "^0.8.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding infection/infection could've been a separate PR :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as #38 (comment) - indeed creeped in too much

{
public function compare(ReflectionClass $fromClass, ReflectionClass $toClass) : Changes
{
Assert::that($fromClass->getName())->same($toClass->getName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not an assumption that's made everywhere anyway...? i.e. afaik, we don't detect git renames

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aye, should probably drop these assertions from all ClassBased checks

return Changes::fromArray([Change::changed(
sprintf('Class %s became a trait', $fromClass->getName()),
true
),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alignment looks wonky here?

/**
* According to the current state of the PHP ecosystem, we only have traits, interfaces and classes
*/
private function isClass(ReflectionClass $class) : bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does ReflectionClass really not have an isClass method... seems like an oversight >.<

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't have one, no. That's because we mimicked the existing ext-reflection API, without designing our own API from scratch upfront.

return Changes::fromArray([Change::changed(
sprintf('Interface %s became a trait', $fromClass->getName()),
true
),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something weird causing these alignment issues in phpcs I expect...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified this: it's an issue in one of the sniffs.

Basically, single-value array should be on a single line, but then the value turns out to be multi-line here. Trying to fix it leads to a phpcs violation being reported, so I'll keep these wonky ones as they are here, and talk to the doctrine folks about it.

}

return Changes::fromArray([Change::changed(
sprintf('Interface %s became a class', $fromTrait->getName()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trait %s became a class

}

return Changes::fromArray([Change::changed(
sprintf('Interface %s became an interface', $fromTrait->getName()),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trait %s became an interface

*/
public static function stringArrayContainsString(string $value, array $arrayOfStrings) : bool
{
Assert::that($arrayOfStrings)->all()->string();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really not sure we need this... seems to just be avoiding false positives; don't know specifically what mutations phpstan performs, but adding an integer onto this array shouldn't be a problem if the expected value is still in there (because we (were) using "strict" mode)... Think this conversation should be moved to a discussion upstream in phpstan, not solved with a wrapper IMO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #38 (comment) for reasoning for this class first.

As for the assertion:

seems to just be avoiding false positives;

We use the in_array()-ish check mostly where reflection returns something to us. As PHP has no way to check type invariants on array values, having a type assertion is still probably a good idea. Can drop it, of course.

@Ocramius
Copy link
Member Author

@asgrim feedback incorporated into the patch, but I'll keep the in_array() replacement in it for now

Copy link
Member

@asgrim asgrim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK 👍 let's :shipit:

@asgrim asgrim merged commit ad68300 into master Apr 26, 2018
@asgrim asgrim deleted the feature/return-type-contravariance-checking branch April 26, 2018 08:59
uzibhalepu added a commit to uzibhalepu/BackwardCompatibilityCheck that referenced this pull request Aug 6, 2024
uzibhalepu added a commit to uzibhalepu/BackwardCompatibilityCheck that referenced this pull request Aug 6, 2024
uzibhalepu added a commit to uzibhalepu/BackwardCompatibilityCheck that referenced this pull request Aug 6, 2024
uzibhalepu added a commit to uzibhalepu/BackwardCompatibilityCheck that referenced this pull request Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants