'Resolve the getattr of \'token\' on the given \'elem\'.
Raises CodeIntelError if could not resolve it.
Algorithm:
- Try to resolve it.
- Call a hook to make an educated guess. Some attribute names
are strong signals as to the object type -- typically those
for common built-in classes.'

def _hit_from_getattr(self, elem, scoperef, token):

    self.log("resolve    getattr    '%s'    on    %r    in    %r:", token, elem, scoperef)
    if (elem.tag == 'variable'):
        hits = self._hits_from_variable_type_inference(elem, scoperef)
    elif ((elem.tag == 'scope') and (elem.get('ilk') == 'function')):
        hits = self._hits_from_type_inference('Function', scoperef)
    else:
        assert (elem.tag == 'scope'), ("elem    tag    is    not    'scope':    %r" % elem.tag)
        hits = [(elem, scoperef)]
    for (hit_elem, hit_scoperef) in hits:
        self.log('_hit_from_getattr::    hit    elem    %r,    scoperef:    %r', hit_elem, hit_scoperef)
        ilk = hit_elem.get('ilk')
        if (hit_elem.tag == 'variable'):
            attr = hit_elem.names.get(token)
            if (attr is not None):
                self.log('attr    is    %r    on    %r', attr, hit_elem)
                var_scoperef = (hit_scoperef[0], (hit_scoperef[1] + [hit_elem.get('name')]))
                return (attr, var_scoperef)
        elif (ilk == 'function'):
            return self._hit_from_getattr(hit_elem, hit_scoperef, token)
        elif (ilk == 'class'):
            attr = hit_elem.names.get(token)
            if (attr is not None):
                self.log('attr    is    %r    on    %r', attr, hit_elem)
                if hit_scoperef:
                    class_scoperef = (hit_scoperef[0], (hit_scoperef[1] + [hit_elem.get('name')]))
                    lineno = int(attr.get('line', '-1'))
                    if ((attr.tag == 'variable') and (lineno > int(hit_elem.get('line', '-1'))) and (lineno <= int(hit_elem.get('lineend', '-1')))):
                        (blob, lpath) = self.buf.scoperef_from_blob_and_line(hit_elem, lineno)
                        if lpath:
                            class_scoperef = (class_scoperef[0], (class_scoperef[1] + lpath))
                            self.log('Updating    scoperef    to:    %r', class_scoperef)
                else:
                    class_scoperef = (None, [hit_elem.get('name')])
                return (attr, class_scoperef)
            for classref in hit_elem.get('classrefs', '').split():
                try:
                    base_hits = self._hits_from_type_inference(classref, hit_scoperef)
                except CodeIntelError:
                    pass
                else:
                    for (base_elem, base_scoperef) in base_hits:
                        if (token in base_elem.names):
                            self.log("is    '%s'    from    %s    base    class?    yes", token, base_elem)
                            new_scoperef = (base_scoperef[0], (base_scoperef[1] + [base_elem.get('name')]))
                            return (base_elem.names[token], new_scoperef)
                        self.log("is    '%s'    from    %s    base    class?    no", token, base_elem)
        else:
            raise NotImplementedError(('unexpected    scope    ilk:    %r' % ilk))
    raise CodeIntelError(("could    not    resolve    '%s'    getattr    on    %r    in    %r" % (token, elem, scoperef)))
