package com.intellij.javascript.flex.mxml;
import com.intellij.lang.javascript.JavaScriptSupportLoader;
import com.intellij.lang.javascript.flex.XmlBackedJSClassImpl;
import com.intellij.lang.javascript.psi.JSExpression;
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.lang.javascript.psi.ecmal4.JSReferenceList;
import com.intellij.lang.javascript.types.JSFileElementType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.containers.HashMap;
import com.intellij.util.indexing.*;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
public abstract class FlexXmlBackedClassesIndex extends ScalarIndexExtension<String> {
private static final int INDEX_VERSION = 4;
@Override
@NotNull
public DataIndexer<String, Void, FileContent> getIndexer() {
return new DataIndexer<String, Void, FileContent>() {
@Override
@NotNull
public Map<String, Void> map(@NotNull FileContent inputData) {
final XmlFile file = (XmlFile)inputData.getPsiFile();
final Map<String, Void> result = new HashMap<>();
for (JSClass clazz : XmlBackedJSClassImpl.getClasses(file)) {
JSReferenceList supers = getSupers(clazz);
if (supers != null) {
final JSExpression[] expressions = supers.getExpressions();
for (JSExpression expr : expressions) {
String s = expr instanceof JSReferenceExpression ? ((JSReferenceExpression)expr).getReferenceName() : null;
if (s != null) result.put(s, null);
}
}
}
return result;
}
};
}
@Nullable
protected abstract JSReferenceList getSupers(JSClass clazz);
@NotNull
@Override
public KeyDescriptor<String> getKeyDescriptor() {
return EnumeratorStringDescriptor.INSTANCE;
}
@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return new DefaultFileTypeSpecificInputFilter(JavaScriptSupportLoader.getMxmlFileType()) {
@Override
public boolean acceptInput(@NotNull VirtualFile file) {
return JavaScriptSupportLoader.isMxmlOrFxgFile(file);
}
};
}
@Override
public boolean dependsOnFileContent() {
return true;
}
@Override
public int getVersion() {
return JSFileElementType.getVersion() + INDEX_VERSION;
}
public static Collection<JSClass> searchClassInheritors(ID<String, Void> indexId, String name, Project project, final GlobalSearchScope scope) {
final Collection<VirtualFile> files = FileBasedIndex.getInstance().getContainingFiles(indexId, name, scope);
final PsiManager psiManager = PsiManager.getInstance(project);
Collection<JSClass> classes = new ArrayList<>(files.size());
for (VirtualFile file : files) {
PsiFile psifile = psiManager.findFile(file);
if (!(psifile instanceof XmlFile)) continue;
classes.addAll(XmlBackedJSClassImpl.getClasses((XmlFile)psifile));
}
if (FlexNameAlias.CONTAINER_TYPE_NAME.equals(name)) {
classes.addAll(searchClassInheritors(indexId, FlexNameAlias.COMPONENT_TYPE_NAME, project, scope));
}
return classes;
}
}