Fix calculation of direct required ancestors
commit8d85fd8059cb5a5b4916bbd6baa30bb6d81d0ef5
authorSasha Manzyuk <manzyuk@fb.com>
Fri, 6 Dec 2019 12:52:01 +0000 (6 04:52 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 6 Dec 2019 12:56:49 +0000 (6 04:56 -0800)
treea0f3d982a75f6625bd71e0b0f9dc3552892f0c31
parent3fa47d8e56eb1cdff97459c7399d55aea11438cc
Fix calculation of direct required ancestors

Summary:
The heap API for fetching class decls offers functions for fetching the set of *all* ancestors and the set of *all* required ancestored (acquired through `require extends` and `require implements`).  Given these, we calculate the set of *direct* ancestors (to be put into `extends` and `implements` clauses) and the set of *direct* required ancestors (to be added by placing suitable `require extends` / `require implements` in the body of a trait or interface).  We calculate these sets by subtracting from the set of all ancestors the set of all ancestors' ancestors.  Except that for required ancestors we calculate the ancestors' ancestors by taking the union of all required ancestors of the required ancestors of a given trait or interface, which is not correct.  Consider this example (added as a new test case below):
```
abstract class B {
  public function f(): void {}
}

interface I {
  require extends B;
}

interface J extends I {}

function with_indirect_require_extends(J $x): void {
  $x->f();
}
```
The set of required ancestors of `J` is `{B}` and `B` doesn't have require ancestors, so we end up with `{B}` as the set of direct required ancestors of `J`, and similarly for `I`, so that the extracted code looks like
```
interface I {
  require extends B;
}

interface J extends I {
  require extends B;
}
```
Instead, we should take the union of all required ancestors over all ancestors and required ancestors.

Reviewed By: Wilfred

Differential Revision: D18764680

fbshipit-source-id: fff08335e23fd990d767470e3acd04ee0423782a
hphp/hack/src/server/serverExtractStandalone.ml
hphp/hack/test/integration/data/dependencies/classes-interfaces.php
hphp/hack/test/integration/data/dependencies/expected/__with_indirect_require_extends.php.exp [new file with mode: 0644]
hphp/hack/test/integration/test_extract_standalone.py