package fr.adrienbrault.idea.symfony2plugin.config.xml.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlTag;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class XmlDuplicateServiceKeyInspection extends LocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) {
if(!Symfony2ProjectComponent.isEnabled(holder.getProject())) {
return super.buildVisitor(holder, isOnTheFly);
}
return new PsiElementVisitor() {
@Override
public void visitFile(PsiFile file) {
visitRoot(file, holder, "services", "service", "id");
super.visitFile(file);
}
};
}
protected void visitRoot(PsiFile psiFile, @NotNull ProblemsHolder holder, String root, String child, String tagName) {
XmlDocument xmlDocument = PsiTreeUtil.getChildOfType(psiFile, XmlDocument.class);
if(xmlDocument == null) {
return;
}
Map<String, XmlAttribute> psiElementMap = new HashMap<>();
Set<XmlAttribute> yamlKeyValues = new HashSet<>();
for(XmlTag xmlTag: PsiTreeUtil.getChildrenOfTypeAsList(psiFile.getFirstChild(), XmlTag.class)) {
if(xmlTag.getName().equals("container")) {
for(XmlTag servicesTag: xmlTag.getSubTags()) {
if(servicesTag.getName().equals(root)) {
for(XmlTag parameterTag: servicesTag.getSubTags()) {
if(parameterTag.getName().equals(child)) {
XmlAttribute keyAttr = parameterTag.getAttribute(tagName);
if(keyAttr != null) {
String parameterName = keyAttr.getValue();
if(parameterName != null && StringUtils.isNotBlank(parameterName)) {
if(psiElementMap.containsKey(parameterName)) {
yamlKeyValues.add(psiElementMap.get(parameterName));
yamlKeyValues.add(keyAttr);
} else {
psiElementMap.put(parameterName, keyAttr);
}
}
}
}
}
}
}
}
}
if(yamlKeyValues.size() > 0) {
for(PsiElement psiElement: yamlKeyValues) {
XmlAttributeValue valueElement = ((XmlAttribute) psiElement).getValueElement();
if(valueElement != null) {
holder.registerProblem(valueElement, "Duplicate Key", ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
}
}
}
}