public static function analyzeElementReferenceCounts(CodeBase $code_base, AddressableElement $element, string $issue_type)
{
// Don't worry about internal elements
if ($element->isInternal()) {
return;
}
// Skip methods that are overrides of other methods
if ($element instanceof ClassElement) {
if ($element->getIsOverride()) {
return;
}
$class_fqsen = $element->getClassFQSEN();
// Don't analyze elements defined in a parent
// class
if ((string) $class_fqsen !== $element->getFQSEN()) {
return;
}
$defining_class = $element->getClass($code_base);
// Don't analyze elements on interfaces or on
// abstract classes, as they're uncallable.
if ($defining_class->isInterface() || $defining_class->isAbstract() || $defining_class->isTrait()) {
return;
}
// Ignore magic methods
if ($element instanceof Method) {
// Doubly nested so that `$element` shows
// up as Method in Phan.
if ($element->getIsMagic()) {
return;
}
}
}
// Skip properties on classes that have a magic
// __get or __set method given that we can't track
// their access
if ($element instanceof Property) {
$defining_class = $element->getClass($code_base);
if ($defining_class->hasGetOrSetMethod($code_base)) {
return;
}
}
/*
print "digraph G {\n";
foreach ($element->getReferenceList() as $file_ref) {
print "\t\"{$file_ref->getFile()}\" -> \"{$element->getFileRef()->getFile()}\";\n";
}
print "}\n";
*/
if ($element->getReferenceCount($code_base) < 1) {
if ($element->hasSuppressIssue($issue_type)) {
return;
}
if ($element instanceof AddressableElement) {
Issue::maybeEmit($code_base, $element->getContext(), $issue_type, $element->getFileRef()->getLineNumberStart(), (string) $element->getFQSEN());
} else {
Issue::maybeEmit($code_base, $element->getContext(), $issue_type, $element->getFileRef()->getLineNumberStart(), (string) $element);
}
}
}