package com.intellij.lang.javascript.flex.debug; import com.intellij.javascript.flex.mxml.MxmlJSClass; import com.intellij.lang.javascript.psi.JSField; import com.intellij.lang.javascript.psi.JSFunction; import com.intellij.lang.javascript.psi.ecmal4.JSAttributeList; import com.intellij.lang.javascript.psi.ecmal4.JSClass; import com.intellij.openapi.util.Iconable; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.Processor; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.Map; public class NodeClassInfo { public final String myFqn; public final boolean myIsDynamic; public final Map<String, Icon> myOwnStaticFields; public final Map<String, Icon> myOwnStaticProperties; public final Map<String, Icon> myOwnFields; public final Map<String, Icon> myOwnProperties; public final Map<String, Icon> myInheritedStaticFields; public final Map<String, Icon> myInheritedStaticProperties; public final Map<String, Icon> myInheritedFields; public final Map<String, Icon> myInheritedProperties; public NodeClassInfo(final String fqn, final boolean dynamic, final Map<String, Icon> ownStaticFields, final Map<String, Icon> ownStaticProperties, final Map<String, Icon> ownFields, final Map<String, Icon> ownProperties, final Map<String, Icon> inheritedStaticFields, final Map<String, Icon> inheritedStaticProperties, final Map<String, Icon> inheritedFields, final Map<String, Icon> inheritedProperties) { myFqn = fqn; myIsDynamic = dynamic; myOwnStaticFields = ownStaticFields; myOwnStaticProperties = ownStaticProperties; myOwnFields = ownFields; myOwnProperties = ownProperties; myInheritedStaticFields = inheritedStaticFields; myInheritedStaticProperties = inheritedStaticProperties; myInheritedFields = inheritedFields; myInheritedProperties = inheritedProperties; } static NodeClassInfo getNodeClassInfo(final @NotNull JSClass jsClass) { final JSAttributeList classAttributes = jsClass.getAttributeList(); final boolean dynamic = classAttributes != null && classAttributes.hasModifier(JSAttributeList.ModifierType.DYNAMIC); final Map<String, Icon> ownStaticFields = new THashMap<>(); final Map<String, Icon> ownStaticProperties = new THashMap<>(); final Map<String, Icon> ownFields = new THashMap<>(); final Map<String, Icon> ownProperties = new THashMap<>(); final Map<String, Icon> inheritedStaticFields = new THashMap<>(); final Map<String, Icon> inheritedStaticProperties = new THashMap<>(); final Map<String, Icon> inheritedFields = new THashMap<>(); final Map<String, Icon> inheritedProperties = new THashMap<>(); fillMapsForClass(jsClass, ownStaticFields, ownStaticProperties, ownFields, ownProperties); fillMapsForSupersRecursively(jsClass, new THashSet<>(), inheritedStaticFields, inheritedStaticProperties, inheritedFields, inheritedProperties); return new NodeClassInfo(normalizeIfVector(jsClass.getQualifiedName()), dynamic, ownStaticFields, ownStaticProperties, ownFields, ownProperties, inheritedStaticFields, inheritedStaticProperties, inheritedFields, inheritedProperties); } private static String normalizeIfVector(final String qName) { return qName.startsWith("Vector$") ? "Vector" : qName; } private static void fillMapsForSupersRecursively(final JSClass jsClass, final THashSet<JSClass> visited, final Map<String, Icon> inheritedStaticFields, final Map<String, Icon> inheritedStaticProperties, final Map<String, Icon> inheritedFields, final Map<String, Icon> inheritedProperties) { if (visited.contains(jsClass)) { return; } visited.add(jsClass); for (final JSClass superClass : jsClass.getSuperClasses()) { fillMapsForClass(superClass, inheritedStaticFields, inheritedStaticProperties, inheritedFields, inheritedProperties); fillMapsForSupersRecursively(superClass, visited, inheritedStaticFields, inheritedStaticProperties, inheritedFields, inheritedProperties); } } private static void fillMapsForClass(final JSClass jsClass, final Map<String, Icon> staticFields, final Map<String, Icon> staticProperties, final Map<String, Icon> fields, final Map<String, Icon> properties) { for (final JSField variable : jsClass.getFields()) { final JSAttributeList varAttributes = variable.getAttributeList(); if (varAttributes != null && varAttributes.hasModifier(JSAttributeList.ModifierType.STATIC)) { staticFields.put(variable.getName(), variable.getIcon(Iconable.ICON_FLAG_VISIBILITY)); } else { fields.put(variable.getName(), variable.getIcon(Iconable.ICON_FLAG_VISIBILITY)); } } for (final JSFunction function : jsClass.getFunctions()) { if (function.getKind() == JSFunction.FunctionKind.GETTER && function.getName() != null) { final JSAttributeList functionAttributes = function.getAttributeList(); if (functionAttributes != null && functionAttributes.hasModifier(JSAttributeList.ModifierType.STATIC)) { staticProperties.put(function.getName(), function.getIcon(Iconable.ICON_FLAG_VISIBILITY)); } else { properties.put(function.getName(), function.getIcon(Iconable.ICON_FLAG_VISIBILITY)); } } } if (jsClass instanceof MxmlJSClass) { final PsiFile file = jsClass.getContainingFile(); final XmlFile xmlFile = file instanceof XmlFile ? (XmlFile)file : null; final XmlTag rootTag = xmlFile == null ? null : xmlFile.getRootTag(); if (rootTag != null) { processSubtagsRecursively(rootTag, tag -> { final String id = tag.getAttributeValue("id"); if (id != null) { fields.put(id, tag.getIcon(Iconable.ICON_FLAG_VISIBILITY)); } return !MxmlJSClass.isTagThatAllowsAnyXmlContent(tag); }); } } } public static void processSubtagsRecursively(final XmlTag tag, final Processor<XmlTag> processor) { for (XmlTag subTag : tag.getSubTags()) { if (processor.process(subTag)) { processSubtagsRecursively(subTag, processor); } } } }