package com.jetbrains.actionscript.profiler.calltree; import com.intellij.util.ArrayUtil; import com.jetbrains.actionscript.profiler.sampler.FrameInfo; import java.util.ArrayList; import java.util.List; class CallerFinder { private CallerFinder() { } /* * Find nodes that call <code>frames</code> in reverse order. * * For example * * <code>foo</code> call <code>bar</code> call <code>baz</code> * <code>bad</code> call <code>bar</code> call <code>foo</code> call <code>baz</code> * <code>frames = [baz, bar]</code> * * Method return only <code>foo</code>. */ static List<CallTreeNode> findCallsByFrames(CallTreeNode root, FrameInfo[] frames) { List<CallTreeNode> calls = new ArrayList<>(); if (frames.length == 0) { return calls; } frames = ArrayUtil.reverseArray(frames); for (CallTreeNode node : root.getChildren()) { fillCallsByFrames(node, calls, frames, new ArrayList<>()); } return calls; } private static void fillCallsByFrames(CallTreeNode currentNode, List<CallTreeNode> result, FrameInfo[] frames, List<FrameInfo> callChainAddedFrames) { //we need only the nearest node to the root //we have <code>callChainAddedFrames<code> boolean needAdd = !callChainAddedFrames.contains(currentNode.getFrameInfo()) && currentNode.getChildDeep(frames) != null; if (needAdd) { result.add(currentNode); callChainAddedFrames.add(currentNode.getFrameInfo()); } for (CallTreeNode childCall : currentNode.getChildren()) { fillCallsByFrames(childCall, result, frames, callChainAddedFrames); } if (needAdd) { //pop callChainAddedFrames.remove(callChainAddedFrames.size() - 1); } } }