| # -*- 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 |