| # -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: |
| #===----------------------------------------------------------------------===## |
| # |
| # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| # |
| #===----------------------------------------------------------------------===## |
| """ |
| diff - A set of functions for diff-ing two symbol lists. |
| """ |
| |
| from libcxx.sym_check import util |
| |
| |
| def _symbol_difference(lhs, rhs): |
| lhs_names = set(((n['name'], n['type']) for n in lhs)) |
| rhs_names = set(((n['name'], n['type']) for n in rhs)) |
| diff_names = lhs_names - rhs_names |
| return [n for n in lhs if (n['name'], n['type']) in diff_names] |
| |
| |
| def _find_by_key(sym_list, k): |
| for sym in sym_list: |
| if sym['name'] == k: |
| return sym |
| return None |
| |
| |
| def added_symbols(old, new): |
| return _symbol_difference(new, old) |
| |
| |
| def removed_symbols(old, new): |
| return _symbol_difference(old, new) |
| |
| |
| def changed_symbols(old, new): |
| changed = [] |
| for old_sym in old: |
| if old_sym in new: |
| continue |
| new_sym = _find_by_key(new, old_sym['name']) |
| if (new_sym is not None and not new_sym in old |
| and old_sym != new_sym): |
| changed += [(old_sym, new_sym)] |
| return changed |
| |
| |
| def diff(old, new): |
| added = added_symbols(old, new) |
| removed = removed_symbols(old, new) |
| changed = changed_symbols(old, new) |
| return added, removed, changed |
| |
| |
| def report_diff(added_syms, removed_syms, changed_syms, names_only=False, |
| demangle=True): |
| def maybe_demangle(name): |
| return util.demangle_symbol(name) if demangle else name |
| |
| report = '' |
| for sym in added_syms: |
| report += 'Symbol added: %s\n' % maybe_demangle(sym['name']) |
| if not names_only: |
| report += ' %s\n\n' % sym |
| if added_syms and names_only: |
| report += '\n' |
| for sym in removed_syms: |
| report += 'SYMBOL REMOVED: %s\n' % maybe_demangle(sym['name']) |
| if not names_only: |
| report += ' %s\n\n' % sym |
| if removed_syms and names_only: |
| report += '\n' |
| if not names_only: |
| for sym_pair in changed_syms: |
| old_sym, new_sym = sym_pair |
| old_str = '\n OLD SYMBOL: %s' % old_sym |
| new_str = '\n NEW SYMBOL: %s' % new_sym |
| report += ('SYMBOL CHANGED: %s%s%s\n\n' % |
| (maybe_demangle(old_sym['name']), |
| old_str, new_str)) |
| |
| added = bool(len(added_syms) != 0) |
| abi_break = bool(len(removed_syms)) |
| if not names_only: |
| abi_break = abi_break or len(changed_syms) |
| if added or abi_break: |
| report += 'Summary\n' |
| report += ' Added: %d\n' % len(added_syms) |
| report += ' Removed: %d\n' % len(removed_syms) |
| if not names_only: |
| report += ' Changed: %d\n' % len(changed_syms) |
| if not abi_break: |
| report += 'Symbols added.' |
| else: |
| report += 'ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!' |
| else: |
| report += 'Symbols match.' |
| is_different = abi_break or bool(len(added_syms)) \ |
| or bool(len(changed_syms)) |
| return report, abi_break, is_different |