public function visitProp(Node $node) : Context
{
$exception_or_null = null;
try {
$property = (new ContextNode($this->code_base, $this->context, $node))->getProperty($node->children['prop']);
// Mark that this property has been referenced from
// this context
$property->addReference($this->context);
} catch (IssueException $exception) {
// We'll check out some reasons it might not exist
// before logging the issue
$exception_or_null = $exception;
} catch (\Exception $exception) {
// Swallow any exceptions. We'll catch it later.
}
if (isset($property)) {
$this->analyzeNoOp($node, Issue::NoopProperty);
} else {
assert(isset($node->children['expr']) || isset($node->children['class']), "Property nodes must either have an expression or class");
$class_list = [];
try {
// Get the set of classes that are being referenced
$class_list = (new ContextNode($this->code_base, $this->context, $node->children['expr'] ?? $node->children['class']))->getClassList(true);
} catch (IssueException $exception) {
Issue::maybeEmitInstance($this->code_base, $this->context, $exception->getIssueInstance());
}
// Find out of any of them have a __get magic method
$has_getter = array_reduce($class_list, function ($carry, $class) {
return $carry || $class->hasGetMethod($this->code_base);
}, false);
// If they don't, then analyze for Noops.
if (!$has_getter) {
$this->analyzeNoOp($node, Issue::NoopProperty);
if ($exception_or_null instanceof IssueException) {
Issue::maybeEmitInstance($this->code_base, $this->context, $exception_or_null->getIssueInstance());
}
}
}
return $this->context;
}