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