def resolve_reference(ref, rel): """Looks up an interrogate symbol to its canonical name. The second argument is the fully qualified name it should be seen relative to, which may be a module name, or a module name followed by an object name. If found, returns a 2-tuple (type, fqname), else None.""" # Find out which module we should be looking in. modname = None relpath = None rel_parts = rel.split('.') for i in range(len(rel_parts), 0, -1): try_modname = '.'.join(rel_parts[:i]) if idb.has_module(try_modname): modname = try_modname relpath = rel_parts[i:] break if not modname: return None refpath = ref.replace('::', '.').split('.') # Say `rel` is "panda3d.core.NodePath.node", # and `ref` is "PandaNode.final", then we will try these in this order: # - panda3d.core::NodePath.node.PandaNode.final # - panda3d.core::NodePath.PandaNode.final # - panda3d.core::PandaNode.final for i in range(len(relpath), -1, -1): search = relpath[:i] + refpath ifunc = idb.lookup_function(modname, search) if ifunc: # Grab the mangled function name. func_name = idb.get_function_name(ifunc, mangle=True) return ('meth', '.'.join(relpath[:i] + refpath[:-1] + [func_name])) itype = idb.lookup_type(modname, search) if itype: # Grab the original type name. type_name = idb.get_type_name(itype, mangle=False, scoped=True) return ('class', type_name)
def resolve_reference(ref, rel, domain='py'): """Looks up an interrogate symbol to its canonical name. The second argument is the fully qualified name it should be seen relative to, which may be a module name, or a module name followed by an object name. If found, returns a 2-tuple (type, fqname), else None.""" # Find out which module we should be looking in. modname = None relpath = None rel_parts = rel.replace('::', '.').split('.') for i in range(len(rel_parts), 0, -1): try_modname = '.'.join(rel_parts[:i]) if idb.has_module(try_modname): modname = try_modname relpath = rel_parts[i:] break if not modname: return None refpath = ref.replace('::', '.').split('.') # Say `rel` is "panda3d.core.NodePath.node", # and `ref` is "PandaNode.final", then we will try these in this order: # - panda3d.core::NodePath.node.PandaNode.final # - panda3d.core::NodePath.PandaNode.final # - panda3d.core::PandaNode.final for i in range(len(relpath), -1, -1): search = relpath[:i] + refpath if len(refpath) == 1 and i > 0 and refpath[0] == relpath[i - 1]: # If we are looking for a name equal to the parent scope, we are # probably referencing a class name from within that very class. # We don't want to find the constructor, so skip this. continue ifunc = idb.lookup_function(modname, search) if ifunc: if domain == 'cpp': func_name = interrogate_function_scoped_name(ifunc) return ('func', func_name) elif domain == 'py': # Grab the mangled function name. func_name = idb.get_function_name(ifunc, mangle=True) if len(search) == 1: return ('func', func_name) else: return ('meth', '.'.join(relpath[:i] + refpath[:-1] + [func_name])) itype = idb.lookup_type(modname, search) if itype: # Grab the original type name. if domain == 'cpp': type_name = interrogate_type_scoped_name(itype) if interrogate_type_is_typedef(itype): return ('type', type_name) elif interrogate_type_is_enum(itype): return ('enum', type_name) elif interrogate_type_is_struct(itype): return ('struct', type_name) elif interrogate_type_is_class(itype): return ('class', type_name) elif interrogate_type_is_union(itype): return ('union', type_name) elif domain == 'py': type_name = idb.get_type_name(itype, mangle=False, scoped=True) return ('class', type_name) if len(rel_parts ) >= 2 and rel_parts[0] == 'panda3d' and rel_parts[1] != 'core': # Look in panda3d.core instead, prefix the result with the module name. rel_parts[1] = 'core' resolved = resolve_reference(ref, '.'.join(rel_parts), domain=domain) if resolved and domain == 'py': return (resolved[0], 'panda3d.core.' + resolved[1]) else: return resolved