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