diff options
Diffstat (limited to 'utils/libcxx/sym_check/diff.py')
| -rw-r--r-- | utils/libcxx/sym_check/diff.py | 103 | 
1 files changed, 103 insertions, 0 deletions
diff --git a/utils/libcxx/sym_check/diff.py b/utils/libcxx/sym_check/diff.py new file mode 100644 index 000000000000..0821ef6f780a --- /dev/null +++ b/utils/libcxx/sym_check/diff.py @@ -0,0 +1,103 @@ +# -*- Python -*- vim: set syntax=python tabstop=4 expandtab cc=80: +#===----------------------------------------------------------------------===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is dual licensed under the MIT and the University of Illinois Open +# Source Licenses. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===## +""" +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'] for n in lhs)) +    rhs_names = set((n['name'] for n in rhs)) +    diff_names = lhs_names - rhs_names +    return [n for n in lhs if n['name'] 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  | 
