package com.jetbrains.actionscript.profiler.sampler; import com.intellij.lang.javascript.psi.JSFunction; import com.intellij.lang.javascript.psi.ecmal4.JSClass; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.jetbrains.actionscript.profiler.base.QNameProducer; import org.jetbrains.annotations.Nullable; import java.io.File; /** * @author: Fedor.Korotkov */ public class FrameInfo implements Comparable<FrameInfo>, QNameProducer { public static final FrameInfo[] EMPTY_FRAME_INFO_ARRAY = new FrameInfo[0]; private int fileLine; private final String qName; @Nullable private final String fileDirectory; @Nullable private final String fileName; @Nullable private final String packageName; @Nullable private final String methodName; @Nullable private final JSFunction.FunctionKind kind; @Nullable private final String namespace; protected FrameInfo(@Nullable String fileDirectory, @Nullable String fileName, int fileLine, @Nullable String packageName, String qName, @Nullable String methodName, @Nullable JSFunction.FunctionKind kind, @Nullable String namespace) { this.fileDirectory = fileDirectory; this.fileName = fileName; this.fileLine = fileLine; this.packageName = packageName; this.qName = qName; this.methodName = methodName; this.kind = kind; this.namespace = namespace; } @Nullable public String getFilePath() { if (getFileDirectory() == null) { return getFileName(); } final StringBuilder pathBuilder = new StringBuilder(); pathBuilder.append(getFileDirectory()); if (packageName != null) { pathBuilder.append(File.separator); pathBuilder.append(packageName.replace('.', File.separatorChar)); } pathBuilder.append(File.separator); pathBuilder.append(getFileName()); return pathBuilder.toString(); } @Nullable public String getFileDirectory() { return fileDirectory; } @Nullable public String getFileName() { return fileName; } public int getFileLine() { return fileLine; } public void setFileLine(int fileLine) { this.fileLine = fileLine; } @Nullable public String getPackageName() { return packageName; } @Override public String getQName() { return qName; } @Nullable public String getMethodName() { return methodName; } @Nullable public JSFunction.FunctionKind getKind() { return kind; } @Nullable public String getNamespace() { return namespace; } public boolean isSystem() { return qName.length() == 0; } public boolean isAnonymous() { return "Function".equals(getQName()) && "<anonymous>".equals(getMethodName()); } public boolean isInnerClass() { return !getClassName().equals(getClassNameByFileName()); } public String getClassName() { String className = getQName(); int i = className.lastIndexOf('.'); if (i != -1 && className.charAt(i + 1) == '<') { final String temp = className.substring(0, i); i = temp.lastIndexOf('.'); } if (i != -1) { className = className.substring(i + 1); } return className; } public String toSimpleString() { return getBuilderWithBasicInfo().toString(); } @Override public String toString() { StringBuilder builder = getBuilderWithBasicInfo(); if (getPackageName() != null) { builder.insert(0, getPackageName()); } if (fileName != null) { builder.append("["); builder.append(fileName); builder.append(":"); builder.append(fileLine); builder.append("]"); } return builder.toString(); } private StringBuilder getBuilderWithBasicInfo() { StringBuilder builder = new StringBuilder(); builder.append(getClassName()); if (getClassName().length() > 0 && methodName != null) { builder.append("."); } if (kind != null) { builder.append(kind == JSFunction.FunctionKind.GETTER ? "get" : "set"); builder.append(" "); } if (methodName != null) { builder.append(methodName); } return builder; } @Override public boolean equals(Object obj) { if (!(obj instanceof FrameInfo)) { return false; } FrameInfo other = (FrameInfo)obj; boolean result = getClassName().equals(other.getClassName()); result = result && StringUtil.equals(getPackageName(), other.getPackageName()); result = result && StringUtil.equals(methodName, other.getMethodName()); result = result && kind == other.getKind(); if (isAnonymous() ^ other.isAnonymous()) { return false; } else if (isAnonymous() && other.isAnonymous()) { result = result && StringUtil.equals(fileName, other.getFileName()); result = result && fileLine == other.getFileLine(); } return result; } @Override public int hashCode() { int result = getClassName().hashCode(); if (packageName != null) { result = 31 * result + packageName.hashCode(); } if (methodName != null) { result = 31 * result + methodName.hashCode(); } if (kind != null) { result = 31 * result + kind.hashCode(); } if (isAnonymous() && fileName != null) { result = 31 * result + fileName.hashCode(); } if (isAnonymous()) { result += fileLine; } return result; } @Override public int compareTo(FrameInfo o) { int tmp = StringUtil.compare(getClassName(), o.getClassName(), false); if (tmp != 0) return tmp; tmp = StringUtil.compare(getMethodName(), o.getMethodName(), false); if (tmp != 0) return tmp; tmp = StringUtil.compare(getPackageName(), o.getPackageName(), false); if (tmp != 0) return tmp; if (kind != null) { tmp = kind.compareTo(o.getKind()); } if (!isAnonymous()) { return tmp; } tmp = StringUtil.compare(getPackageName(), o.getPackageName(), false); if (tmp != 0) return tmp; tmp = StringUtil.compare(getFileName(), o.getFileName(), false); if (tmp != 0) return tmp; return fileLine - o.getFileLine(); } @Nullable public String getClassNameByFileName() { String result = getFileName(); if (result == null) { return null; } int i = result.lastIndexOf('.'); if (i != -1) { return result.substring(0, i); } return result; } @Nullable public String getQNameByFile() { String qName = getPackageName(); qName = qName != null ? qName.replace(File.separatorChar, '.') + '.' : ""; String className = getClassNameByFileName(); if (className == null) { return null; } return qName + className; } @Nullable public PsiElement findFunctionOrField(JSClass clazz) { PsiElement result = kind != null ? clazz.findFunctionByNameAndKind(methodName, kind) : clazz.findFunctionByName(methodName); if (result == null && (kind == JSFunction.FunctionKind.GETTER || kind == JSFunction.FunctionKind.SETTER)) { //generated getter/setter in case of binding result = clazz.findFieldByName(methodName); } if (result == null && methodName != null && methodName.startsWith("__")) { //generated handler int i = methodName.lastIndexOf('_'); if (i > 2) { result = clazz.findFieldByName(methodName.substring(2, i)); } } return result; } }