1# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: 2# ===----------------------------------------------------------------------===## 3# 4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5# See https://llvm.org/LICENSE.txt for license information. 6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7# 8# ===----------------------------------------------------------------------===## 9""" 10diff - A set of functions for diff-ing two symbol lists. 11""" 12 13from libcxx.sym_check import util 14 15 16def _symbol_difference(lhs, rhs): 17 lhs_names = set(((n["name"], n["type"]) for n in lhs)) 18 rhs_names = set(((n["name"], n["type"]) for n in rhs)) 19 diff_names = lhs_names - rhs_names 20 return [n for n in lhs if (n["name"], n["type"]) in diff_names] 21 22 23def _find_by_key(sym_list, k): 24 for sym in sym_list: 25 if sym["name"] == k: 26 return sym 27 return None 28 29 30def added_symbols(old, new): 31 return _symbol_difference(new, old) 32 33 34def removed_symbols(old, new): 35 return _symbol_difference(old, new) 36 37 38def changed_symbols(old, new): 39 changed = [] 40 for old_sym in old: 41 if old_sym in new: 42 continue 43 new_sym = _find_by_key(new, old_sym["name"]) 44 if new_sym is not None and not new_sym in old and old_sym != new_sym: 45 changed += [(old_sym, new_sym)] 46 return changed 47 48 49def diff(old, new): 50 added = added_symbols(old, new) 51 removed = removed_symbols(old, new) 52 changed = changed_symbols(old, new) 53 return added, removed, changed 54 55 56def report_diff( 57 added_syms, removed_syms, changed_syms, names_only=False, demangle=True 58): 59 def maybe_demangle(name): 60 return util.demangle_symbol(name) if demangle else name 61 62 report = "" 63 for sym in added_syms: 64 report += "Symbol added: %s\n" % maybe_demangle(sym["name"]) 65 if not names_only: 66 report += " %s\n\n" % sym 67 if added_syms and names_only: 68 report += "\n" 69 for sym in removed_syms: 70 report += "SYMBOL REMOVED: %s\n" % maybe_demangle(sym["name"]) 71 if not names_only: 72 report += " %s\n\n" % sym 73 if removed_syms and names_only: 74 report += "\n" 75 if not names_only: 76 for sym_pair in changed_syms: 77 old_sym, new_sym = sym_pair 78 old_str = "\n OLD SYMBOL: %s" % old_sym 79 new_str = "\n NEW SYMBOL: %s" % new_sym 80 report += "SYMBOL CHANGED: %s%s%s\n\n" % ( 81 maybe_demangle(old_sym["name"]), 82 old_str, 83 new_str, 84 ) 85 86 added = bool(len(added_syms) != 0) 87 abi_break = bool(len(removed_syms)) 88 if not names_only: 89 abi_break = abi_break or len(changed_syms) 90 if added or abi_break: 91 report += "Summary\n" 92 report += " Added: %d\n" % len(added_syms) 93 report += " Removed: %d\n" % len(removed_syms) 94 if not names_only: 95 report += " Changed: %d\n" % len(changed_syms) 96 if not abi_break: 97 report += "Symbols added." 98 else: 99 report += "ABI BREAKAGE: SYMBOLS ADDED OR REMOVED!" 100 else: 101 report += "Symbols match." 102 is_different = abi_break or bool(len(added_syms)) or bool(len(changed_syms)) 103 return report, abi_break, is_different 104