Fail if there are two AST nodes with the same fullname reachable from 'o'. Raise AssertionError on failure and print some debugging output.
(o: object)
| 12 | |
| 13 | |
| 14 | def check_consistency(o: object) -> None: |
| 15 | """Fail if there are two AST nodes with the same fullname reachable from 'o'. |
| 16 | |
| 17 | Raise AssertionError on failure and print some debugging output. |
| 18 | """ |
| 19 | seen, parents = get_reachable_graph(o) |
| 20 | reachable = list(seen.values()) |
| 21 | syms = [x for x in reachable if isinstance(x, SymbolNode)] |
| 22 | |
| 23 | m: dict[str, SymbolNode] = {} |
| 24 | for sym in syms: |
| 25 | if isinstance(sym, FakeInfo): |
| 26 | continue |
| 27 | |
| 28 | fn = sym.fullname |
| 29 | # Skip None and empty names, since they are ambiguous. |
| 30 | # TODO: Everything should have a proper full name? |
| 31 | if not fn: |
| 32 | continue |
| 33 | |
| 34 | # Skip stuff that should be expected to have duplicate names |
| 35 | if isinstance(sym, (Var, Decorator)): |
| 36 | continue |
| 37 | if isinstance(sym, FuncDef) and sym.is_overload: |
| 38 | continue |
| 39 | |
| 40 | if fn not in m: |
| 41 | m[fn] = sym |
| 42 | continue |
| 43 | |
| 44 | # We have trouble and need to decide what to do about it. |
| 45 | sym1, sym2 = sym, m[fn] |
| 46 | |
| 47 | # If the type changed, then it shouldn't have been merged. |
| 48 | if type(sym1) is not type(sym2): |
| 49 | continue |
| 50 | |
| 51 | path1 = get_path(sym1, seen, parents) |
| 52 | path2 = get_path(sym2, seen, parents) |
| 53 | |
| 54 | if fn in m: |
| 55 | print(f"\nDuplicate {type(sym).__name__!r} nodes with fullname {fn!r} found:") |
| 56 | print("[1] %d: %s" % (id(sym1), path_to_str(path1))) |
| 57 | print("[2] %d: %s" % (id(sym2), path_to_str(path2))) |
| 58 | |
| 59 | if DUMP_MISMATCH_NODES and fn in m: |
| 60 | # Add verbose output with full AST node contents. |
| 61 | print("---") |
| 62 | print(id(sym1), sym1) |
| 63 | print("---") |
| 64 | print(id(sym2), sym2) |
| 65 | |
| 66 | assert sym.fullname not in m |
| 67 | |
| 68 | |
| 69 | def path_to_str(path: list[tuple[object, object]]) -> str: |
searching dependent graphs…