aboutsummaryrefslogtreecommitdiff
path: root/utils/libcxx/sym_check/diff.py
diff options
context:
space:
mode:
Diffstat (limited to 'utils/libcxx/sym_check/diff.py')
-rw-r--r--utils/libcxx/sym_check/diff.py103
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