Enforce modularity boundaries for classes
[hiphop-php.git] / hphp / test / slow / facts / facts.php
blobf61ad5fd93fdaed6b652cc13aeedf5f94df26484
1 <?hh
3 /**
4 * Return the relative path of an absolute path.
6 * Assumes that this directory is the root directory.
7 */
8 function relative_path(string $path): string {
9 if (strlen($path) === 0 || $path[0] !== '/') {
10 return $path;
12 $root = __DIR__;
13 $offset = strpos($path, $root);
14 if ($offset < 0) {
15 print "FAILURE: $path does not begin with $root\n";
17 return substr($path, $offset + strlen($root) + 1);
20 function jsonify_arr(Container<arraykey> $arr): string {
21 $arr = vec($arr);
22 \sort(inout $arr);
23 return json_encode($arr);
26 function jsonify_filters(HH\Facts\DeriveFilters $filters): string {
27 $filters_for_json = dict[];
28 $kinds = Shapes::idx($filters, 'kind');
29 if ($kinds is Container<_>) {
30 $kinds = vec($kinds);
31 \sort(inout $kinds);
32 $filters_for_json['kind'] = $kinds;
34 $derive_kinds = Shapes::idx($filters, 'derive_kind');
35 if ($derive_kinds is Container<_>) {
36 $derive_kinds = vec($derive_kinds);
37 \sort(inout $derive_kinds);
38 $filters_for_json['derive_kind'] = $derive_kinds;
40 $attributes = Shapes::idx($filters, 'attributes');
41 if ($attributes is Container<_>) {
42 $attributes = vec($attributes);
43 \sort(inout $attributes);
44 $filters_for_json['attributes'] = $attributes;
47 return json_encode($filters_for_json);
50 function print_kind(classname<mixed> $type): void {
51 $kind = HH\Facts\kind($type);
52 if ($kind is null) {
53 print "$type has no kind\n";
54 } else {
55 print "$type is $kind\n";
59 function print_subtypes(
60 classname<mixed> $type,
61 ?HH\Facts\DeriveFilters $filters = null,
62 ): void {
63 if ($filters is nonnull) {
64 $subtypes_json = jsonify_arr(HH\Facts\subtypes($type, $filters));
65 $filters_json = jsonify_filters($filters);
66 print "Subtypes of $type with filters $filters_json: $subtypes_json\n";
67 } else {
68 $subtypes_json = jsonify_arr(HH\Facts\subtypes($type));
69 print "Subtypes of $type: $subtypes_json\n";
73 function print_transitive_subtypes(
74 classname<mixed> $type,
75 ?HH\Facts\DeriveFilters $filters = null,
76 ): void {
77 if ($filters is nonnull) {
78 $subtypes_json = jsonify_arr(HH\Facts\transitive_subtypes(
79 $type,
80 $filters,
81 ));
82 $filters_json = jsonify_filters($filters);
83 print "Transitive subtypes of $type with filters $filters_json: ".
84 "$subtypes_json\n";
85 } else {
86 $subtypes_json = jsonify_arr(HH\Facts\transitive_subtypes($type));
87 print "Transitive subtypes of $type: $subtypes_json\n";
91 function print_supertypes(
92 classname<mixed> $type,
93 ?HH\Facts\DeriveFilters $filters = null,
94 ): void {
95 if ($filters is nonnull) {
96 $supertypes_json = jsonify_arr(HH\Facts\supertypes($type, $filters));
97 $filters_json = jsonify_filters($filters);
98 print "Supertypes of $type with filters $filters_json: $supertypes_json\n";
99 } else {
100 $supertypes_json = jsonify_arr(HH\Facts\supertypes($type));
101 print "Supertypes of $type: $supertypes_json\n";
105 function print_type_attrs(
106 classname<mixed> $type,
107 ): void {
108 $attrs = dict[];
109 foreach (HH\Facts\type_attributes($type) as $attr) {
110 $attrs[$attr] = HH\Facts\type_attribute_parameters($type, $attr);
112 \ksort(inout $attrs);
113 $attrs_json = \json_encode($attrs);
114 print "Attributes of $type: $attrs_json\n";
117 function print_type_alias_attrs(
118 string $type_alias,
119 ): void {
120 $attrs = dict[];
121 foreach (HH\Facts\type_alias_attributes($type_alias) as $attr) {
122 $attrs[$attr] = HH\Facts\type_alias_attribute_parameters(
123 $type_alias,
124 $attr,
127 \ksort(inout $attrs);
128 $attrs_json = \json_encode($attrs);
129 print "Attributes of $type_alias: $attrs_json\n";
132 function print_method_attrs(
133 classname<nonnull> $type,
134 string $method,
135 ): void {
136 $attrs = dict[];
137 foreach (HH\Facts\method_attributes($type, $method) as $attr) {
138 $attrs[$attr] = HH\Facts\method_attribute_parameters($type, $method, $attr);
140 \ksort(inout $attrs);
141 $attrs_json = \json_encode($attrs);
142 print "Attributes of $type::$method: $attrs_json\n";
145 function print_file_attrs(
146 string $file,
147 ): void {
148 $attrs = dict[];
149 foreach (HH\Facts\file_attributes($file) as $attr) {
150 $attrs[$attr] = HH\Facts\file_attribute_parameters($file, $attr);
152 \ksort(inout $attrs);
153 $attrs_json = \json_encode($attrs);
154 print "Attributes of $file: $attrs_json\n";
157 function print_attr_types(
158 classname<\HH\ClassAttribute> $attr,
159 ): void {
160 $types = HH\Facts\types_with_attribute($attr);
161 \sort(inout $types);
162 $types_json = \json_encode($types);
163 print "Types decorated with $attr: $types_json\n";
166 function print_attr_type_aliases(
167 classname<\HH\ClassAttribute> $attr,
168 ): void {
169 $type_aliases = HH\Facts\type_aliases_with_attribute($attr);
170 \sort(inout $type_aliases);
171 $type_aliases_json = \json_encode($type_aliases);
172 print "Type aliases decorated with $attr: $type_aliases_json\n";
175 function print_attr_methods(
176 classname<\HH\MethodAttribute> $attr,
177 ): void {
178 $method_tuples = HH\Facts\methods_with_attribute($attr);
179 $methods = vec[];
180 foreach ($method_tuples as list($type, $method)) {
181 $methods[] = "$type::$method";
183 \sort(inout $methods);
184 $methods_json = \json_encode($methods);
185 print "Methods decorated with $attr: $methods_json\n";
188 function print_attr_files(
189 classname<\HH\FileAttribute> $attr,
190 ): void {
191 $files = HH\Facts\files_with_attribute($attr);
192 \sort(inout $files);
193 $files_json = \json_encode($files);
194 print "Files decorated with $attr: $files_json\n";
197 function print_num_symbols(
198 string $path,
199 ): void {
200 $types = HH\Facts\path_to_types($path);
201 $num_types = \count($types);
202 print "$path has $num_types types\n";
204 $functions = HH\Facts\path_to_functions($path);
205 $num_functions = \count($functions);
206 print "$path has $num_functions functions\n";
208 $constants = HH\Facts\path_to_constants($path);
209 $num_constants = \count($constants);
210 print "$path has $num_constants constants\n";
212 $type_aliases = HH\Facts\path_to_type_aliases($path);
213 $num_type_aliases = \count($type_aliases);
214 print "$path has $num_type_aliases type aliases\n";
217 function print_extracted_facts(vec<string> $files): void {
218 $files_with_null_hashes = vec[];
219 foreach ($files as $file) {
220 $files_with_null_hashes[] = tuple($file, null);
222 foreach (
223 HH\Facts\extract($files_with_null_hashes) as $file => $facts
225 print "Facts in $file:\n";
227 print " types:\n";
228 foreach ($facts['types'] as $type) {
229 $name = $type['name'];
230 print " name: $name\n";
232 $kind = $type['kind'];
233 print " kind: $kind\n";
235 $flags = $type['flags'];
236 print " flags: $flags\n";
238 $base_types = $type['baseTypes'];
239 \sort(inout $base_types);
240 $base_types_json = \json_encode($base_types);
241 print " baseTypes: $base_types_json\n";
243 $require_extends = $type['requireExtends'];
244 \sort(inout $require_extends);
245 $require_extends_json = \json_encode($require_extends);
246 print " requireExtends: $require_extends_json\n";
248 $require_implements = $type['requireImplements'];
249 \sort(inout $require_implements);
250 $require_implements_json = \json_encode($require_implements);
251 print " requireImplements: $require_implements_json\n";
253 $attributes = $type['attributes'];
254 \usort(
255 inout $attributes,
256 ($attr1, $attr2) ==> $attr1['name'] <=> $attr2['name'],
258 $attributes_json = \json_encode($attributes);
259 print " attributes: $attributes_json\n";
261 $methods = $type['methods'];
262 \usort(
263 inout $methods,
264 ($m1, $m2) ==> $m1['name'] <=> $m2['name'],
266 $methods_json = \json_encode($methods);
267 print " methods: $methods_json\n";
270 $functions = $facts['functions'];
271 \sort(inout $functions);
272 $functions_json = \json_encode($functions);
273 print " functions: $functions_json\n";
275 $constants = $facts['constants'];
276 \sort(inout $constants);
277 $constants_json = \json_encode($constants);
278 print " constants: $constants_json\n";
280 $attributes = $facts['attributes'];
281 \usort(
282 inout $attributes,
283 ($attr1, $attr2) ==> $attr1['name'] <=> $attr2['name'],
285 $attributes_json = \json_encode($attributes);
286 print " attributes: $attributes_json\n";
288 $sha1 = $facts['sha1sum'];
289 print " sha1sum: $sha1\n";
293 <<__EntryPoint>>
294 function facts(): void {
295 var_dump(HH\Facts\enabled());
297 var_dump(HH\Facts\TypeKind::K_CLASS);
298 var_dump(HH\Facts\TypeKind::K_ENUM);
299 var_dump(HH\Facts\TypeKind::K_INTERFACE);
300 var_dump(HH\Facts\TypeKind::K_TRAIT);
302 print_kind(BaseClass::class);
303 print_kind(DerivedClass::class);
305 print_kind(C1::class);
306 print_kind(E1::class);
307 print_kind(I1::class);
308 print_kind(T1::class);
309 print_kind(Nonexistent::class);
311 print_subtypes(BaseClass::class);
312 print_supertypes(BaseClass::class);
314 print_subtypes(
315 IBase::class,
316 shape('kind' => keyset[HH\Facts\TypeKind::K_CLASS]),
318 print_transitive_subtypes(
319 IBase::class,
320 shape('kind' => keyset[HH\Facts\TypeKind::K_CLASS]),
322 print_subtypes(
323 IBase::class,
324 shape('kind' => keyset[HH\Facts\TypeKind::K_TRAIT]),
326 print_transitive_subtypes(
327 IBase::class,
328 shape('kind' => keyset[HH\Facts\TypeKind::K_TRAIT]),
330 print_subtypes(
331 IBase::class,
332 shape(
333 'kind' => keyset[
334 HH\Facts\TypeKind::K_CLASS,
335 HH\Facts\TypeKind::K_TRAIT,
339 print_transitive_subtypes(
340 IBase::class,
341 shape(
342 'kind' => keyset[
343 HH\Facts\TypeKind::K_CLASS,
344 HH\Facts\TypeKind::K_TRAIT,
349 print_supertypes(DerivedClass::class);
350 print_supertypes(
351 DerivedClass::class,
352 shape('kind' => keyset[HH\Facts\TypeKind::K_CLASS]),
354 print_supertypes(
355 DerivedClass::class,
356 shape('kind' => keyset[HH\Facts\TypeKind::K_TRAIT]),
358 print_supertypes(
359 DerivedClass::class,
360 shape('kind' => keyset[HH\Facts\TypeKind::K_INTERFACE]),
362 print_supertypes(
363 DerivedClass::class,
364 shape(
365 'kind' => keyset[
366 HH\Facts\TypeKind::K_CLASS,
367 HH\Facts\TypeKind::K_TRAIT,
371 print_supertypes(
372 DerivedClass::class,
373 shape(
374 'kind' => keyset[
375 HH\Facts\TypeKind::K_INTERFACE,
376 HH\Facts\TypeKind::K_TRAIT,
381 print "\nExcluding `require extends` relations\n";
383 print_subtypes(
384 IBase::class,
385 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
387 print_transitive_subtypes(
388 IBase::class,
389 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
391 print_subtypes(
392 BaseClass::class,
393 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
395 print_transitive_subtypes(
396 BaseClass::class,
397 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
399 print_supertypes(
400 TRequireExtendsBaseClassAndRequireImplementsIBase::class,
401 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
403 print_supertypes(
404 TRequireImplementsAndImplementsIBase::class,
405 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS]),
407 print_subtypes(
408 IBase::class,
409 shape(
410 'kind' => keyset[HH\Facts\TypeKind::K_INTERFACE],
411 'derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS],
414 print_transitive_subtypes(
415 IBase::class,
416 shape(
417 'kind' => keyset[HH\Facts\TypeKind::K_INTERFACE],
418 'derive_kind' => keyset[HH\Facts\DeriveKind::K_EXTENDS],
422 print "\nExcluding `extends` relations\n";
424 print_subtypes(
425 IBase::class,
426 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
428 print_subtypes(
429 BaseClass::class,
430 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
432 print_transitive_subtypes(
433 IBase::class,
434 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
436 print_supertypes(
437 TRequireExtendsBaseClassAndRequireImplementsIBase::class,
438 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
440 print_transitive_subtypes(
441 BaseClass::class,
442 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
444 print_supertypes(
445 TRequireImplementsAndImplementsIBase::class,
446 shape('derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS]),
448 print_supertypes(
449 SomeEnum::class,
450 shape('kind' => keyset[HH\Facts\TypeKind::K_CLASS]),
452 print_subtypes(
453 IBase::class,
454 shape(
455 'kind' => keyset[HH\Facts\TypeKind::K_INTERFACE],
456 'derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS],
459 print_transitive_subtypes(
460 IBase::class,
461 shape(
462 'kind' => keyset[HH\Facts\TypeKind::K_INTERFACE],
463 'derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS],
466 print_subtypes(
467 IBase::class,
468 shape(
469 'kind' => keyset[HH\Facts\TypeKind::K_TRAIT],
470 'derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS],
473 print_transitive_subtypes(
474 IBase::class,
475 shape(
476 'kind' => keyset[HH\Facts\TypeKind::K_TRAIT],
477 'derive_kind' => keyset[HH\Facts\DeriveKind::K_REQUIRE_EXTENDS],
481 print "\nFiltering by attribute\n";
483 print_subtypes(
484 BaseClassForAttributeFiltering::class,
485 shape('attributes' => vec[shape(
486 'name' => TwoArgAttr::class,
487 'parameters' => dict[0 => "banana"],
488 )]),
490 print_transitive_subtypes(
491 IBaseForAttributeFiltering::class,
492 shape('attributes' => vec[shape(
493 'name' => TwoArgAttr::class,
494 'parameters' => dict[0 => "banana"],
495 )]),
497 print_subtypes(
498 BaseClassForAttributeFiltering::class,
499 shape('attributes' => vec[shape(
500 'name' => TwoArgAttr::class,
501 'parameters' => dict[0 => 'apple'],
502 )]),
504 print_transitive_subtypes(
505 IBaseForAttributeFiltering::class,
506 shape('attributes' => vec[shape(
507 'name' => TwoArgAttr::class,
508 'parameters' => dict[0 => 'apple'],
509 )]),
511 print_subtypes(
512 BaseClassForAttributeFiltering::class,
513 shape('attributes' => vec[shape(
514 'name' => TwoArgAttr::class,
515 'parameters' => dict[1 => 'carrot'],
516 )]),
518 print_transitive_subtypes(
519 IBaseForAttributeFiltering::class,
520 shape('attributes' => vec[shape(
521 'name' => TwoArgAttr::class,
522 'parameters' => dict[1 => 'carrot'],
523 )]),
526 print "\nGetting attributes\n";
528 print_type_attrs(AppleThenBanana::class);
529 print_type_attrs(BananaThenApple::class);
530 print_type_attrs(AppleThenCarrot::class);
531 print_type_attrs(ClassWithTwoAttrs::class);
532 print_type_alias_attrs(TypeAliasWithAttr::class);
533 print_method_attrs(ClassWithMethodAttrs::class, 'methodWithNoArgAttr');
534 print_method_attrs(ClassWithMethodAttrs::class, 'methodWithTwoArgAttr');
536 print
537 "\nThese should be empty, otherwise we're mixing types and type aliases ".
538 "up again\n";
539 print_type_alias_attrs(ClassWithTwoAttrs::class);
540 print_type_attrs(TypeAliasWithAttr::class);
542 print "\nGetting types with attribute\n";
543 print_attr_types(NoArgAttr::class);
544 print_attr_types(TwoArgAttr::class);
545 print_attr_methods(NoArgMethodAttr::class);
546 print_attr_methods(TwoArgMethodAttr::class);
548 print "\nGetting type aliases with attribute\n";
549 print_attr_type_aliases(TypeAliasAttr::class);
551 print "\nGetting file attributes\n";
552 print_attr_files(NoArgFileAttr::class);
553 print_attr_files(TwoArgFileAttr::class);
554 print_file_attrs('attribute-classes.inc');
556 print "\nChecking nonexistent paths\n";
557 print_num_symbols('this/path/does/not/exist.php');
558 print_num_symbols('/this/path/does/not/exist.php');
560 print "\nGetting all types\n";
561 $all_types = HH\Facts\all_types();
562 \ksort(inout $all_types);
563 foreach ($all_types as $type => $path) {
564 $is_abstract = HH\Facts\is_abstract($type) ? 'true' : 'false';
565 $is_final = HH\Facts\is_final($type) ? 'true' : 'false';
566 print "$type => $path\n";
567 print " Abstract? $is_abstract\n";
568 print " Final? $is_final\n";
569 $facts_path = relative_path(HH\Facts\type_to_path($type) as nonnull);
570 if ($facts_path !== $path) {
571 print "FAILURE: $facts_path !== $path\n";
574 print "\nGetting all functions\n";
575 $all_functions = HH\Facts\all_functions();
576 \ksort(inout $all_functions);
577 foreach ($all_functions as $function => $path) {
578 print "$function => $path\n";
579 $facts_path = relative_path(
580 HH\Facts\function_to_path($function) as nonnull,
582 if ($facts_path !== $path) {
583 print "FAILURE: $facts_path !== $path\n";
586 print "\nGetting all constants\n";
587 $all_constants = HH\Facts\all_constants();
588 \ksort(inout $all_constants);
589 foreach ($all_constants as $constant => $path) {
590 print "$constant => $path\n";
591 $facts_path = relative_path(
592 HH\Facts\constant_to_path($constant) as nonnull,
594 if ($facts_path !== $path) {
595 print "FAILURE: $facts_path !== $path\n";
598 print "\nGetting all type aliases\n";
599 $all_type_aliases = HH\Facts\all_type_aliases();
600 \ksort(inout $all_type_aliases);
601 foreach ($all_type_aliases as $type_alias => $path) {
602 print "$type_alias => $path\n";
603 $facts_path = relative_path(
604 HH\Facts\type_alias_to_path($type_alias) as nonnull,
606 if ($facts_path !== $path) {
607 print "FAILURE: $facts_path !== $path\n";
611 print_extracted_facts(
612 vec[
613 'attribute-classes.inc',
614 'attribute-namespace.inc',
615 'base-class.inc',
616 'constants.inc',
617 'derived-class.inc',
618 'type_aliases.inc',
619 'types-with-kinds.inc',
622 print "Finished.\n";