nodes: 0, module; 1, function_definition; 2, function_name:_widening_points; 3, parameters; 4, block; 5, identifier:self; 6, identifier:function_address; 7, expression_statement; 8, comment:# we are entering a new function. now it's time to figure out how to optimally traverse the control flow; 9, comment:# graph by generating the sorted merge points; 10, try_statement; 11, if_statement; 12, return_statement; 13, comment:"""
          Return the ordered widening points for a specific function.
  
          :param int function_address: Address of the querying function.
          :return: A list of sorted merge points (addresses).
          :rtype: list
          """; 14, block; 15, except_clause; 16, comparison_operator:function_address not in self._function_widening_points; 17, block; 18, subscript; 19, expression_statement; 20, identifier:KeyError; 21, comment:# the function does not exist; 22, block; 23, identifier:function_address; 24, attribute; 25, if_statement; 26, expression_statement; 27, expression_statement; 28, attribute; 29, identifier:function_address; 30, assignment; 31, return_statement; 32, identifier:self; 33, identifier:_function_widening_points; 34, not_operator; 35, block; 36, assignment; 37, assignment; 38, identifier:self; 39, identifier:_function_widening_points; 40, identifier:new_function; 41, subscript; 42, list; 43, attribute; 44, expression_statement; 45, identifier:widening_points; 46, call; 47, subscript; 48, identifier:widening_points; 49, attribute; 50, identifier:function_address; 51, identifier:new_function; 52, identifier:normalized; 53, call; 54, attribute; 55, argument_list; 56, attribute; 57, identifier:function_address; 58, attribute; 59, identifier:functions; 60, attribute; 61, argument_list; 62, identifier:CFGUtils; 63, identifier:find_widening_points; 64, identifier:function_address; 65, attribute; 66, attribute; 67, identifier:self; 68, identifier:_function_widening_points; 69, identifier:self; 70, identifier:kb; 71, identifier:new_function; 72, identifier:normalize; 73, identifier:new_function; 74, identifier:endpoints; 75, identifier:new_function; 76, identifier:graph
code: def _widening_points(self, function_address):
          """
          Return the ordered widening points for a specific function.
  
          :param int function_address: Address of the querying function.
          :return: A list of sorted merge points (addresses).
          :rtype: list
          """
  
          # we are entering a new function. now it's time to figure out how to optimally traverse the control flow
          # graph by generating the sorted merge points
          try:
              new_function = self.kb.functions[function_address]
          except KeyError:
              # the function does not exist
              return [ ]
  
          if function_address not in self._function_widening_points:
              if not new_function.normalized:
                  new_function.normalize()
              widening_points = CFGUtils.find_widening_points(function_address, new_function.endpoints,
                                                                      new_function.graph)
              self._function_widening_points[function_address] = widening_points
  
          return self._function_widening_points[function_address]