# -*- coding: utf-8 -*- """找出 MainActivity 里**定义了但没人调用**的私有方法。 为什么需要这个:2.3.0 把一半的分页删了,原来那些按钮背后的方法 就全变成孤儿了。一个个跑测试太慢,先用这个脚本一次性列出来。 排除规则(这些"没人调用"是正常的): * @Override 的回调(框架会调) * 生命周期方法(onCreate/onPause/...) * 构造器 * 只有 setVisibility / setText 之类直接操作的不算 """ from __future__ import annotations import re import sys from pathlib import Path JAVA = (Path(__file__).resolve().parent.parent / "android" / "src" / "com" / "lanremote" / "watch" / "MainActivity.java") # 框架调用的,不算孤儿 LIFECYCLE = { "onCreate", "onStart", "onResume", "onPause", "onStop", "onDestroy", "onActivityResult", "onRequestPermissionsResult", "onBackPressed", "onNewIntent", "onSaveInstanceState", "onRestoreInstanceState", "onTouchEvent", "onKeyDown", "onConfigurationChanged", "onWindowFocusChanged", "onCreateOptionsMenu", "onOptionsItemSelected", "onClick", "run", "onPrepared", "onCompletion", "onError", "onProgressChanged", "onStartTrackingTouch", "onStopTrackingTouch", "onSingleTapConfirmed", "onDoubleTap", "onScroll", "onFling", "onDown", "onLongPress", "onShowPress", "onSingleTapUp", "onInput", "onPick", "onResponse", "onFailure", "doInBackground", "onPostExecute", "beforeTextChanged", "onTextChanged", "afterTextChanged", "onItemClick", "onItemSelected", "onNothingSelected", "onFocusChange", "onEditorAction", } # 定义方法的各种写法 DEF_RE = re.compile( r"^[ \t]*(?:@\w+(?:\([^)]*\))?\s*)*" r"(?:private|protected|public|static|final|synchronized|\s)*" r"(?:[\w<>\[\],.?\s]+?)\s+(\w+)\s*\([^)]*\)\s*(?:throws [\w,.\s]+)?\s*\{", re.M) def main() -> int: text = JAVA.read_text(encoding="utf-8") lines = text.split("\n") # 收集定义(带行号) defs = [] for i, ln in enumerate(lines): m = DEF_RE.match(ln) if not m: continue name = m.group(1) # 排除构造器(名字等于类名)和 exclude 集合 if name in ("MainActivity", "if", "for", "while", "switch", "catch"): continue # 排除紧跟在 @Override 后面的 prev = [x.strip() for x in lines[max(0, i - 3):i]] if any("_override_" == p or "@Override" in p for p in prev): continue defs.append((name, i + 1)) # 统计每个名字被调用多少次(排除定义行自己) def_line = {} for name, ln in defs: def_line.setdefault(name, set()).add(ln) orphans = [] for name, ln in defs: # 统计调用次数:名字 + "(" 出现次数 occurrences = [(i + 1, l) for i, l in enumerate(lines) if re.search(r"\b" + re.escape(name) + r"\s*\(", l)] # 减去定义本身那一行 calls = [o for o in occurrences if o[0] != ln] # 定义行可能是多行签名的第一行,精确匹配名字出现的所有行 if not calls: if name not in LIFECYCLE: orphans.append((name, ln)) print(" 定义的方法 %d 个" % len(defs)) print(" 孤儿方法 %d 个:" % len(orphans)) for name, ln in orphans: print(" 第 %-5d %s()" % (ln, name)) # 也检查被调用但只出现在注释里的(可能是残留引用) print() print(" 被删除后仍被引用的符号(编译错误来源):") deleted = sys.argv[1:] if len(sys.argv) > 1 else [] for sym in deleted: hits = [(i + 1, l.strip()) for i, l in enumerate(lines) if re.search(r"\b" + re.escape(sym) + r"\s*\(", l)] if hits: # 判断是不是定义行 deflines = {d[1] for d in defs if d[0] == sym} real = [h for h in hits if h[0] not in deflines] if real: print(" %s: %d 处调用" % (sym, len(real))) for ln, l in real[:5]: print(" 第 %d: %s" % (ln, l[:100])) return 0 if __name__ == "__main__": sys.exit(main())