# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Utilities for demangling C++ symbols."""

import collections
import itertools
import logging
import re
import subprocess

import path_util

_LOWER_HEX_PATTERN = re.compile(r'^[0-9a-f]*$')
_PROMOTED_GLOBAL_NAME_DEMANGLED_PATTERN = re.compile(
    r' \((\.\d+)?\.llvm\.\d+\)$')
_PROMOTED_GLOBAL_NAME_RAW_PATTERN = re.compile(r'(\.\d+)?\.llvm\.\d+$')

def StripLlvmPromotedGlobalNames(name):
  """Strips LLVM promoted global names suffix, and returns the result.

  LLVM can promote global names by adding the suffix '.llvm.1234', or
  '.1.llvm.1234', where the last numeric suffix is a hash. If demangle is
  sucessful, the suffix transforms into, e.g., ' (.llvm.1234)' or
  ' (.1.llvm.1234)'. Otherwise the suffix is left as is. This function strips
  the suffix to prevent it from intefering with name comparison.
  """
  llvm_pos = name.find('.llvm.')
  if llvm_pos < 0:
    return name  # Handles most cases.
  if name.endswith(')'):
    return _PROMOTED_GLOBAL_NAME_DEMANGLED_PATTERN.sub('', name)
  return _PROMOTED_GLOBAL_NAME_RAW_PATTERN.sub('', name)


def _CanDemangle(name):
  return name.startswith('_Z') or name.startswith('.Lswitch.table._Z')


def _ExtractDemanglablePart(names):
  """For each name in |names|, yields the part that can be demangled."""

  def _IsLowerHex(s):
    return _LOWER_HEX_PATTERN.match(s) is not None

  for name in names:
    # Strip prefixes before '_Z', e.g., '.Lswitch.table.'.
    pos = name.find('_Z')
    if pos > 0:
      name = name[pos:]

    # Some mangled symbols end with '$' followed by 32 lower-case hex digits,
    # and possibly '.cfi'. These interfere with demangling by cxxfilt, and
    # should be stripped.
    if name.endswith('.cfi'):
      name = name[:-4]
    if len(name) > 33 and name[-33] == '$' and _IsLowerHex(name[-32:]):
      yield name[:-33]
    else:
      yield name


def _PostProcessDemangledSymbol(old_name, new_name):
  new_name = StripLlvmPromotedGlobalNames(new_name)
  if old_name.startswith('.Lswitch.table.'):
    new_name = 'Switch table for ' + new_name  # Becomes ... [Switch table].
  return new_name


def _DemangleNames(names):
  """Uses cxxfilt to demangle a list of names."""
  # pylint: disable=unexpected-keyword-arg
  proc = subprocess.Popen([path_util.GetCppFiltPath()],
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          encoding='utf-8')
  in_data = '\n'.join(_ExtractDemanglablePart(names))
  stdout = proc.communicate(in_data)[0]
  assert proc.returncode == 0
  ret = [
      _PostProcessDemangledSymbol(old_name, new_name)
      for (old_name, new_name) in zip(names, stdout.splitlines())
  ]
  if logging.getLogger().isEnabledFor(logging.INFO):
    fail_count = sum(1 for s in ret if _CanDemangle(s))
    if fail_count:
      logging.info('* Failed to demangle %d/%d items', fail_count, len(ret))
  return ret


def DemangleRemainingSymbols(raw_symbols):
  """Demangles any symbols that need it."""
  to_process = [s for s in raw_symbols if _CanDemangle(s.full_name)]
  if not to_process:
    return

  logging.info('Demangling %d symbols', len(to_process))
  names = _DemangleNames([s.full_name for s in to_process])
  for i, name in enumerate(names):
    to_process[i].full_name = name


def DemangleSetsInDictsInPlace(key_to_names):
  """Demangles values as sets.

  |key_to_names| is a dict from key to sets (or lists) of mangled names.
  """
  all_names = []
  for names in key_to_names.values():
    all_names.extend(n for n in names if _CanDemangle(n))
  if not all_names:
    return key_to_names

  logging.info('Demangling %d values', len(all_names))
  it = iter(_DemangleNames(all_names))
  for key, names in key_to_names.items():
    key_to_names[key] = set(next(it) if _CanDemangle(n) else n for n in names)
  assert(next(it, None) is None)

  return None


def DemangleKeysAndMergeLists(name_to_list):
  """Demangles keys of a dict of lists, and returns the result.

  Keys may demangle to a common name. When this happens, the corresponding lists
  are merged in arbitrary order.
  """
  keys = [key for key in name_to_list if _CanDemangle(key)]
  if not keys:
    return name_to_list

  logging.info('Demangling %d keys', len(keys))
  key_iter = iter(_DemangleNames(keys))
  ret = collections.defaultdict(list)
  for key, val in name_to_list.items():
    ret[next(key_iter) if _CanDemangle(key) else key] += val
  assert(next(key_iter, None) is None)
  logging.info('* %d keys become %d keys' % (len(name_to_list), len(ret)))
  return ret
