Home | History | Annotate | Download | only in sym_check
      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 """
     11 diff - A set of functions for diff-ing two symbol lists.
     12 """
     13 
     14 from sym_check import util
     15 
     16 
     17 def _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 
     24 def _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 
     31 def added_symbols(old, new):
     32     return _symbol_difference(new, old)
     33 
     34 
     35 def removed_symbols(old, new):
     36     return _symbol_difference(old, new)
     37 
     38 
     39 def 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 cmp(old_sym, new_sym) != 0):
     47             changed += [(old_sym, new_sym)]
     48     return changed
     49 
     50 
     51 def 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 
     58 def 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     return report, int(abi_break)
    102