diff --git a/src/applications/diviner/controller/DivinerAtomController.php b/src/applications/diviner/controller/DivinerAtomController.php --- a/src/applications/diviner/controller/DivinerAtomController.php +++ b/src/applications/diviner/controller/DivinerAtomController.php @@ -35,11 +35,6 @@ return new Aphront404Response(); } - // TODO: This query won't load ghosts, because they'll fail `needAtoms()`. - // Instead, we might want to load ghosts and render a message like - // "this thing existed in an older version, but no longer does", especially - // if we add content like comments. - $symbol = id(new DivinerAtomQuery()) ->setViewer($viewer) ->withBookPHIDs(array($book->getPHID())) @@ -47,6 +42,7 @@ ->withNames(array($this->atomName)) ->withContexts(array($this->atomContext)) ->withIndexes(array($this->atomIndex)) + ->withIncludeGhosts(true) ->needAtoms(true) ->needExtends(true) ->needChildren(true) @@ -64,9 +60,9 @@ $book->getShortTitle(), '/book/'.$book->getName().'/'); - $atom_short_title = $atom->getDocblockMetaValue( - 'short', - $symbol->getTitle()); + $atom_short_title = $atom + ? $atom->getDocblockMetaValue('short', $symbol->getTitle()) + : $symbol->getTitle(); $crumbs->addTextCrumb($atom_short_title); @@ -76,11 +72,12 @@ id(new PHUITagView()) ->setType(PHUITagView::TYPE_STATE) ->setBackgroundColor(PHUITagView::COLOR_BLUE) - ->setName(DivinerAtom::getAtomTypeNameString($atom->getType()))); + ->setName(DivinerAtom::getAtomTypeNameString( + $atom ? $atom->getType() : $symbol->getType()))); $properties = id(new PHUIPropertyListView()); - $group = $atom->getProperty('group'); + $group = $atom ? $atom->getProperty('group') : $symbol->getGroupName(); if ($group) { $group_name = $book->getGroupName($group); } else { @@ -90,7 +87,7 @@ $this->buildDefined($properties, $symbol); $this->buildExtendsAndImplements($properties, $symbol); - $warnings = $atom->getWarnings(); + $warnings = $atom ? $atom->getWarnings() : array(); if ($warnings) { $warnings = id(new PHUIInfoView()) ->setErrors($warnings) @@ -128,6 +125,13 @@ ->appendChild($warnings) ->appendChild($content); + if (!$atom) { + $document->appendChild( + id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild(pht('This atom is gone.'))); + } + $document->appendChild($this->buildParametersAndReturn(array($symbol))); if ($methods) { @@ -340,6 +344,10 @@ DivinerLiveSymbol $symbol) { $atom = $symbol->getAtom(); + if (!$atom) { + return; + } + $defined = $atom->getFile().':'.$atom->getLine(); $link = $symbol->getBook()->getConfig('uri.source'); @@ -471,20 +479,23 @@ $atom = $symbol->getAtom(); $out = array(); - if ($atom->getProperty('final')) { - $out[] = 'final'; - } - if ($atom->getProperty('abstract')) { - $out[] = 'abstract'; - } + if ($atom) { + if ($atom->getProperty('final')) { + $out[] = 'final'; + } - if ($atom->getProperty('access')) { - $out[] = $atom->getProperty('access'); - } + if ($atom->getProperty('abstract')) { + $out[] = 'abstract'; + } + + if ($atom->getProperty('access')) { + $out[] = $atom->getProperty('access'); + } - if ($atom->getProperty('static')) { - $out[] = 'static'; + if ($atom->getProperty('static')) { + $out[] = 'static'; + } } switch ($symbol->getType()) { @@ -528,7 +539,7 @@ $out = phutil_implode_html(' ', $out); - $parameters = $atom->getProperty('parameters'); + $parameters = $atom ? $atom->getProperty('parameters') : null; if ($parameters !== null) { $pout = array(); foreach ($parameters as $parameter) { @@ -552,7 +563,13 @@ $out = array(); $collected_parameters = null; + $parameters = array(); + foreach ($symbols as $symbol) { + if (!$symbol->getAtom()) { + continue; + } + $parameters = $symbol->getAtom()->getProperty('parameters'); if ($parameters !== null) { if ($collected_parameters === null) { @@ -575,7 +592,13 @@ } $collected_return = null; + $return = array(); + foreach ($symbols as $symbol) { + if (!$symbol->getAtom()) { + continue; + } + $return = $symbol->getAtom()->getProperty('return'); if ($return) { if ($collected_return) { @@ -602,6 +625,10 @@ $field = 'default'; $content = $engine->getOutput($symbol, $field); + if (!$symbol->getAtom()) { + return; + } + if (strlen(trim($symbol->getMarkupText($field)))) { $content = phutil_tag( 'div', @@ -634,6 +661,10 @@ $out = array(); foreach ($symbols as $key => $symbol) { + if (!$symbol->getAtom()) { + continue; + } + $impl = $implementations[$key]; if ($impl !== $parent) { if (!strlen(trim($symbol->getMarkupText($field)))) { diff --git a/src/applications/diviner/query/DivinerAtomQuery.php b/src/applications/diviner/query/DivinerAtomQuery.php --- a/src/applications/diviner/query/DivinerAtomQuery.php +++ b/src/applications/diviner/query/DivinerAtomQuery.php @@ -155,7 +155,7 @@ foreach ($atoms as $key => $atom) { $data = idx($atom_data, $atom->getPHID()); if (!$data) { - unset($atoms[$key]); + $atom->attachAtom(null); continue; } $atom->attachAtom($data); @@ -173,6 +173,10 @@ $names = array(); foreach ($atoms as $atom) { + if (!$atom->getAtom()) { + continue; + } + foreach ($atom->getAtom()->getExtends() as $xref) { $names[] = $xref->getName(); } @@ -192,10 +196,17 @@ } foreach ($atoms as $atom) { - $alang = $atom->getAtom()->getLanguage(); + $alang = null; + $aextends = array(); + + if ($atom->getAtom()) { + $alang = $atom->getAtom()->getLanguage(); + $aextends = $atom->getAtom()->getExtends(); + } + $extends = array(); - foreach ($atom->getAtom()->getExtends() as $xref) { + foreach ($aextends as $xref) { // If there are no symbols of the matching name and type, we can't // resolve this. if (empty($xatoms[$xref->getName()][$xref->getType()])) { @@ -397,7 +408,13 @@ $hashes = array(); foreach ($symbols as $symbol) { - foreach ($symbol->getAtom()->getChildHashes() as $hash) { + $child_hashes = array(); + + if ($symbol->getAtom()) { + $child_hashes = $symbol->getAtom()->getChildHashes(); + } + + foreach ($child_hashes as $hash) { $hashes[$hash] = $hash; } if ($recurse_up) { @@ -427,8 +444,14 @@ assert_instances_of($children, 'DivinerLiveSymbol'); foreach ($symbols as $symbol) { + $child_hashes = array(); $symbol_children = array(); - foreach ($symbol->getAtom()->getChildHashes() as $hash) { + + if ($symbol->getAtom()) { + $child_hashes = $symbol->getAtom()->getChildHashes(); + } + + foreach ($child_hashes as $hash) { if (isset($children[$hash])) { $symbol_children[] = $children[$hash]; } diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php --- a/src/applications/diviner/storage/DivinerLiveSymbol.php +++ b/src/applications/diviner/storage/DivinerLiveSymbol.php @@ -98,8 +98,12 @@ return $this->assertAttached($this->atom); } - public function attachAtom(DivinerLiveAtom $atom) { - $this->atom = DivinerAtom::newFromDictionary($atom->getAtomData()); + public function attachAtom(DivinerLiveAtom $atom = null) { + if ($atom === null) { + $this->atom = null; + } else { + $this->atom = DivinerAtom::newFromDictionary($atom->getAtomData()); + } return $this; } @@ -229,6 +233,10 @@ public function getMarkupText($field) { + if (!$this->getAtom()) { + return; + } + return $this->getAtom()->getDocblockText(); }