def parse_clang_node(cls, cursor: clang.Cursor, parent: typing.Optional[ir.Node] = None) -> ir.Node: """ Parses a Clang AST node identified by a cursor into an IR node. :param cursor: The cursor pointing to the node. :param parent: The parent IR node. :return: The corresponding IR node. """ type_str = getattr(cursor.type, 'spelling', '') # Build label label = f"{type_str}: {cursor.spelling}" if cursor.is_definition() and type_str else cursor.spelling # Default node data kwargs = dict( typ=cursor.kind.name, label=label, ref=cursor.get_usr(), parent=parent, source_range=cls.get_range(cursor), ) # Overrides for root node if parent is None and cursor.kind == clang.CursorKind.TRANSLATION_UNIT: kwargs['label'] = os.path.basename(kwargs['label']) # Overrides for specific kinds of nodes if cursor.kind in cls._customizers: cls._customizers[cursor.kind](cursor, kwargs) # Build node node = ir.Node(**kwargs) return node
def _populate_function_nodes(self, cursor: ci.Cursor): self.context.push_cursor(cursor) if self.context.has_thrower(): self.context.top_thrower().set_exception_type(self.context) if cursor.kind.name == 'FUNCTION_DECL': usr = cursor.get_usr() assert self.function_nodes[usr].decl is None self.function_nodes[usr].decl = FunctionDecl(usr, cursor.location) self.context.push_function(usr) if cursor.kind.name == 'CALL_EXPR': usr = cursor.referenced.get_usr() # TODO function calls can happen outside of functions # For example, in a global init, or in a lamba in a global init. self.function_nodes[self.context.top_function()].calls.append( FunctionCall(usr, self.context)) self.function_nodes[usr].callers.append( FunctionCall(self.context.top_function(), self.context)) if cursor.kind.name == 'VAR_DECL' and self.context.parent_cursor( ).kind.name == 'CXX_CATCH_STMT': self.context.top_try_block().set_top_catcher_exception_type(cursor) if cursor.kind.name == 'CXX_TRY_STMT': self.context.push_try_block(TryCatch(self.context)) if cursor.kind.name == 'CXX_CATCH_STMT': self.context.top_try_block().add_catcher(Catcher(self.context)) if cursor.kind.name == 'CXX_THROW_EXPR': thrower = Thrower(self.context) self.context.push_thrower(thrower) self.throwers.append(thrower) for child in cursor.get_children(): self._populate_function_nodes(child) if cursor.kind.name == 'FUNCTION_DECL': self.context.pop_funtion() if cursor.kind.name == 'CXX_TRY_STMT': self.context.pop_try_block() if cursor.kind.name == 'CXX_THROW_EXPR': self.context.pop_thrower() self.context.pop_cursor()