2025年5月8日

        /// <summary>
        /// 単一クラス内で、イベントメソッド rootName を起点としたメソッド呼び出し階層を DFS で展開。
        /// 1イベント(rootName)ごとに、同じメソッド名は1回だけ子展開する。
        /// 2回目以降の呼び出しは「(再利用)」として行だけ出力し、子メソッドには潜らない。
        /// 階層表示 = 全角スペース×深さ + (深さ>0なら '∟')+ メソッド名(+(再利用)/(再帰))。
        /// </summary>
        private static void TraverseMethodTreeRows(
            string className,
            string rootName,
            string methodName,
            int depth,
            Dictionary<string, HashSet<string>> adj,
            Dictionary<string, int> lineMap,
            HashSet<string> path,
            HashSet<string> visitedRoot,
            List<object[]> outRows)
        {
            string key = methodName;

            // ① 再帰ループ検出(現在のパス上に既に存在する)
            if (path.Contains(key))
            {
                string baseName = methodName + " (再帰)";
                string lnLoopStr = "";
                int lnLoop;
                if (lineMap.TryGetValue(methodName, out lnLoop))
                {
                    lnLoopStr = lnLoop.ToString();
                }

                string indentR = new string(' ', depth);   // 全角スペース
                string displayR = (depth > 0)
                    ? indentR + "∟" + baseName
                    : baseName;

                outRows.Add(new object[]
                {
                    className,          // 0
                    rootName,           // 1
                    depth.ToString(),   // 2
                    displayR,           // 3 階層表示
                    baseName,           // 4 メソッド名
                    lnLoopStr           // 5 行番号
                });
                return;
            }

            // ② このイベント(rootName)配下で既に子展開済みかどうか
            if (visitedRoot.Contains(methodName))
            {
                // → 行は出すが、子メソッドには潜らない(再利用マークのみ)
                string lnStr2 = "";
                int ln2;
                if (lineMap.TryGetValue(methodName, out ln2))
                {
                    lnStr2 = ln2.ToString();
                }

                string dispName = methodName + " (再利用)";
                string indent2 = new string(' ', depth);   // 全角スペース
                string display2 = (depth > 0)
                    ? indent2 + "∟" + dispName
                    : dispName;

                outRows.Add(new object[]
                {
                    className,          // 0
                    rootName,           // 1
                    depth.ToString(),   // 2
                    display2,           // 3 階層表示
                    dispName,           // 4 メソッド名(再利用)
                    lnStr2              // 5 行番号
                });
                return;
            }

            // ③ 初回出現:今回出力+子展開対象にする
            visitedRoot.Add(methodName);
            path.Add(key);

            string lnStr = "";
            int ln;
            if (lineMap.TryGetValue(methodName, out ln))
            {
                lnStr = ln.ToString();
            }

            string indent = new string(' ', depth);   // 全角スペース
            string display = (depth > 0)
                ? indent + "∟" + methodName
                : methodName;

            outRows.Add(new object[]
            {
                className,           // 0
                rootName,            // 1
                depth.ToString(),    // 2
                display,             // 3 階層表示
                methodName,          // 4 メソッド名
                lnStr                // 5 行番号
            });

            // ④ 子メソッドへ(初回のみ)
            HashSet<string> children;
            if (adj.TryGetValue(methodName, out children))
            {
                List<string> list = new List<string>(children);
                list.Sort((a, b) =>
                {
                    int la = lineMap.ContainsKey(a) ? lineMap[a] : int.MaxValue;
                    int lb = lineMap.ContainsKey(b) ? lineMap[b] : int.MaxValue;
                    if (la != lb) return la.CompareTo(lb);
                    return string.Compare(a, b, StringComparison.Ordinal);
                });

                foreach (string child in list)
                {
                    TraverseMethodTreeRows(
                        className,
                        rootName,
                        child,
                        depth + 1,
                        adj,
                        lineMap,
                        path,
                        visitedRoot,
                        outRows);
                }
            }

            path.Remove(key);
        }

C#

Posted by temochic