package fr.adrienbrault.idea.symfony2plugin.stubs.indexes; import com.intellij.ide.highlighter.XmlFileType; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorIntegerDescriptor; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.KeyDescriptor; import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.yaml.YAMLFileType; import org.jetbrains.yaml.psi.YAMLFile; import org.jetbrains.yaml.psi.YAMLKeyValue; import org.jetbrains.yaml.psi.YAMLSequence; import org.jetbrains.yaml.psi.YAMLValue; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class ContainerIdUsagesStubIndex extends FileBasedIndexExtension<String, Integer> { public static final ID<String, Integer> KEY = ID.create("fr.adrienbrault.idea.symfony2plugin.service_id_usage"); @NotNull @Override public ID<String, Integer> getName() { return KEY; } @NotNull @Override public DataIndexer<String, Integer, FileContent> getIndexer() { return inputData -> { Map<String, Integer> map = new HashMap<>(); PsiFile psiFile = inputData.getPsiFile(); if(!Symfony2ProjectComponent.isEnabledForIndex(psiFile.getProject())) { return map; } if(!ServicesDefinitionStubIndex.isValidForIndex(inputData, psiFile)) { return map; } if(psiFile instanceof YAMLFile) { map.putAll(getIdUsages((YAMLFile) psiFile)); } else if(psiFile instanceof XmlFile) { map.putAll(getIdUsages((XmlFile) psiFile)); } return map; }; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return EnumeratorStringDescriptor.INSTANCE; } @NotNull @Override public DataExternalizer<Integer> getValueExternalizer() { return EnumeratorIntegerDescriptor.INSTANCE; } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return file -> file.getFileType() == XmlFileType.INSTANCE || file.getFileType() == YAMLFileType.YML; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 1; } private static Map<String, Integer> getIdUsages(@NotNull YAMLFile yamlFile) { Map<String, Integer> services = new HashMap<>(); for(YAMLKeyValue yamlKeyValue: YamlHelper.getQualifiedKeyValuesInFile(yamlFile, "services")) { String keyName = yamlKeyValue.getKeyText(); if(StringUtils.isBlank(keyName)) { continue; } YAMLKeyValue arguments = YamlHelper.getYamlKeyValue(yamlKeyValue, "arguments"); if(arguments == null) { continue; } YAMLValue value = arguments.getValue(); if(!(value instanceof YAMLSequence)) { continue; } for (String id : YamlHelper.getYamlArrayValuesAsList((YAMLSequence) value)) { String idClean = YamlHelper.trimSpecialSyntaxServiceName(id); if(StringUtils.isNotBlank(idClean)) { services.putIfAbsent(idClean, 0); services.put(idClean, services.get(idClean) + 1); } } } return services; } private static Map<String, Integer> getIdUsages(@NotNull XmlFile psiFile) { PsiElement firstChild = psiFile.getFirstChild(); if(!(firstChild instanceof XmlDocument)) { return Collections.emptyMap(); } XmlTag rootTag = ((XmlDocument) firstChild).getRootTag(); if(rootTag == null || !"container".equals(rootTag.getName())) { return Collections.emptyMap(); } Map<String, Integer> services = new HashMap<>(); for (XmlTag xmlTag : rootTag.findSubTags("services")) { for (XmlTag service : xmlTag.findSubTags("service")) { for (XmlTag argument : service.findSubTags("argument")) { if("service".equalsIgnoreCase(argument.getAttributeValue("type"))) { String id = argument.getAttributeValue("id"); if(id != null && StringUtils.isNotBlank(id)) { services.putIfAbsent(id, 0); services.put(id, services.get(id) + 1); } } } } } return services; } }