package com.jetbrains.actionscript.profiler.sampler; import com.intellij.lang.javascript.psi.JSFunction; import com.intellij.openapi.util.text.StringUtil; import gnu.trove.THashMap; import java.util.Map; /** * @author: Fedor.Korotkov */ public class FrameInfoBuilder { private final String[] suffixes = {"$", "$cinit()"}; private final Map<String, FrameInfo> cache = new THashMap<>(); private final Map<FrameInfo, FrameInfo> cacheInstances = new THashMap<>(); private final int UNKNOWN_LINE = -1; FrameInfo[] buildInstances(String[] frames) { FrameInfo[] result = new FrameInfo[frames.length]; for (int i = 0; i < frames.length; ++i) { result[i] = buildInstance(frames[i]); } return result; } public FrameInfo buildInstance(String data) { FrameInfo result = cache.get(data); if (result == null) { result = createInstance(data); FrameInfo cashedInstance = cacheInstances.get(result); //do NOT put anonymous in cache if (!result.isAnonymous() && cashedInstance != null) { int fileLine = Math.min(cashedInstance.getFileLine(), result.getFileLine()); if (fileLine != -1) { cashedInstance.setFileLine(fileLine); } result = cashedInstance; } else if (!result.isAnonymous()) { cacheInstances.put(result, result); } cache.put(data, result); } return result; } public FrameInfo createInstance(final String data) { int line = UNKNOWN_LINE; String dir = null; String packageName = null; String filename = null; final int i = data.indexOf('['); final int i2 = data.indexOf(']', i); if (i != -1 && i2 != -1) { // try navigate from debug info [path;package path;file:line] , btw it can be invalid for SDK String s = data.substring(i + 1, i2); int i3 = s.indexOf(';'); int i4 = s.indexOf(';', i3 + 1); if (i3 != -1) { dir = s.substring(0, i3); packageName = s.substring(i3 + 1, i4); filename = s.substring(i4 + 1); packageName = packageName.replace('\\', '.').replace('/', '.'); final int endIndex = filename.indexOf(':'); line = 0; if (endIndex != -1) { line = Integer.parseInt(filename.substring(endIndex + 1)); filename = filename.substring(0, endIndex); } String className = packageName; if (className.length() > 0) className += "."; className += filename.substring(0, filename.indexOf('.')); } } String s = data; if (i != -1) s = s.substring(0, i); int packageEnd = s.indexOf("::"); int methodNameStart = s.indexOf('/'); if (methodNameStart < packageEnd) { //namespace packageEnd = -1; } String qName = methodNameStart != -1 ? s.substring(0, methodNameStart) : s; qName = StringUtil.replace(qName, "::", "."); for (String suffix : suffixes) { if (qName.endsWith(suffix)) { qName = qName.substring(0, qName.length() - suffix.length()); break; } } String methodName = null; String namespace = null; JSFunction.FunctionKind kind = null; final int constructorStart = qName.indexOf('('); if (methodNameStart == -1 && constructorStart != -1) { qName = qName.substring(0, constructorStart); methodName = qName.substring(qName.lastIndexOf('.') + 1); } else if (methodNameStart != -1) { ++methodNameStart; int methodNameEnd = s.indexOf('(', methodNameStart); if (methodNameEnd == -1) methodNameEnd = s.length(); int possibleGetSet = s.indexOf(' ', methodNameStart); final int oldMethodStart = methodNameStart; if (possibleGetSet != -1) methodNameStart = possibleGetSet + 1; methodName = s.substring(methodNameStart, methodNameEnd); final int nsStart = methodName.indexOf("::"); if (nsStart != -1) { namespace = methodName.substring(0, nsStart); methodName = methodName.substring(nsStart + "::".length()); } if (possibleGetSet != -1) { String getOrSet = s.substring(oldMethodStart, possibleGetSet); if ("get".equals(getOrSet)) { kind = JSFunction.FunctionKind.GETTER; } else if ("set".equals(getOrSet)) kind = JSFunction.FunctionKind.SETTER; } if ("ctor".equals(methodName)) { methodName = qName.substring(qName.lastIndexOf('.') + 1); } } if (qName.length() == 0 && data.matches("\\[.*\\]\\(\\)")) { methodName = data.substring(1, data.length() - 3); } if (packageName == null && qName.lastIndexOf('.') != -1) { packageName = qName.substring(0, qName.lastIndexOf('.')); } return new FrameInfo(dir, filename, line, packageName, qName, methodName, kind, namespace); } }