Page MenuHomePhabricator

D11052.id27416.diff
No OneTemporary

D11052.id27416.diff

diff --git a/src/__tests__/PhutilLibraryTestCase.php b/src/__tests__/PhutilLibraryTestCase.php
--- a/src/__tests__/PhutilLibraryTestCase.php
+++ b/src/__tests__/PhutilLibraryTestCase.php
@@ -40,6 +40,67 @@
}
/**
+ * This is more of an acceptance test case instead of a unit test. It verifies
+ * that methods in subclasses have the same visibility as the method in the
+ * parent class.
+ */
+ public function testMethodVisibility() {
+ $symbols = id(new PhutilSymbolLoader())
+ ->selectSymbolsWithoutLoading();
+
+ $classes = array();
+ foreach ($symbols as $symbol) {
+ if ($symbol['type'] == 'class') {
+ $classes[$symbol['name']] = new ReflectionClass($symbol['name']);
+ }
+ }
+
+ $failures = array();
+
+ foreach ($classes as $class_name => $class) {
+ $parents = array();
+ $parent = $class;
+ while ($parent = $parent->getParentClass()) {
+ $parents[] = $parent;
+ }
+
+ $interfaces = $class->getInterfaces();
+
+ foreach ($class->getMethods() as $method) {
+ $visibility = $this->getVisibility($method);
+ $method_name = $method->getName();
+
+ foreach (array_merge($parents, $interfaces) as $extends) {
+ if ($extends->hasMethod($method_name)) {
+ $xmethod = $extends->getMethod($method_name);
+ $xvisibility = $this->getVisibility($xmethod);
+
+ if ($xvisibility != $visibility) {
+ $failures[] = pht(
+ 'Class "%s" implements method "%s" with the wrong visibility. '.
+ 'The method has visibility "%s", but it is defined in parent '.
+ '"%s" with visibility "%s". In Phabricator, a method which '.
+ 'overrides another must always have the same visibility.',
+ $class_name,
+ $method_name,
+ $visibility,
+ $extends->getName(),
+ $xvisibility);
+ }
+
+ // We found a declaration somewhere, so stop looking.
+ break;
+ }
+ }
+ }
+ }
+
+ $this->assertTrue(
+ empty($failures),
+ implode("\n\n", $failures));
+ }
+
+ /**
* Get the root directory for the library currently being tested.
*/
protected function getLibraryRoot() {
@@ -47,4 +108,14 @@
return phutil_get_library_root_for_path($caller);
}
+ private function getVisibility(ReflectionMethod $method) {
+ if ($method->isPrivate()) {
+ return 'private';
+ } else if ($method->isProtected()) {
+ return 'protected';
+ } else {
+ return 'public';
+ }
+ }
+
}

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 28, 8:59 PM (4 m, 29 s)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6941141
Default Alt Text
D11052.id27416.diff (2 KB)

Event Timeline