package fr.adrienbrault.idea.symfony2plugin.intentions.yaml; import com.intellij.codeInspection.*; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent; import fr.adrienbrault.idea.symfony2plugin.action.ServiceActionUtil; import fr.adrienbrault.idea.symfony2plugin.intentions.yaml.dict.YamlCreateServiceArgumentsCallback; import fr.adrienbrault.idea.symfony2plugin.intentions.yaml.dict.YamlUpdateArgumentServicesCallback; import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver; import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.yaml.psi.YAMLFile; import org.jetbrains.yaml.psi.YAMLKeyValue; import java.util.List; import java.util.Set; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class YamlServiceArgumentInspection extends LocalInspectionTool { public static final String[] INVALID_KEYS = new String[]{"parent", "factory_class", "factory_service", "factory_method", "abstract", "factory", "autowire"}; @NotNull public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, boolean isOnTheFly) { if(!Symfony2ProjectComponent.isEnabled(holder.getProject())) { return super.buildVisitor(holder, isOnTheFly); } return new MyPsiElementVisitor(holder); } private static class MyPsiElementVisitor extends PsiElementVisitor { @NotNull private final ProblemsHolder problemsHolder; private ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector; public MyPsiElementVisitor(@NotNull ProblemsHolder problemsHolder) { this.problemsHolder = problemsHolder; } @Override public void visitFile(PsiFile file) { if(!(file instanceof YAMLFile)) { return; } for (ServiceActionUtil.ServiceYamlContainer serviceYamlContainer : ServiceActionUtil.getYamlContainerServiceArguments((YAMLFile) file)) { // we dont support parent services for now if(!isValidService(serviceYamlContainer)) { continue; } List<String> yamlMissingArgumentTypes = ServiceActionUtil.getYamlMissingArgumentTypes(problemsHolder.getProject(), serviceYamlContainer, false, getLazyServiceCollector(problemsHolder.getProject())); if(yamlMissingArgumentTypes != null && yamlMissingArgumentTypes.size() > 0) { problemsHolder.registerProblem(serviceYamlContainer.getServiceKey().getFirstChild(), "Missing argument", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new YamlArgumentQuickfix()); } } this.lazyServiceCollector = null; } private boolean isValidService(ServiceActionUtil.ServiceYamlContainer serviceYamlContainer) { Set<String> keySet = YamlHelper.getKeySet(serviceYamlContainer.getServiceKey()); if(keySet == null) { return true; } for(String s: INVALID_KEYS) { if(keySet.contains(s)) { return false; } } return true; } private ContainerCollectionResolver.LazyServiceCollector getLazyServiceCollector(Project project) { return this.lazyServiceCollector == null ? this.lazyServiceCollector = new ContainerCollectionResolver.LazyServiceCollector(project) : this.lazyServiceCollector; } } private static class YamlArgumentQuickfix implements LocalQuickFix { @NotNull @Override public String getName() { return "Symfony: Yaml Argument"; } @NotNull @Override public String getFamilyName() { return "Symfony"; } @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) { final PsiElement serviceKeyValue = problemDescriptor.getPsiElement().getParent(); if(!(serviceKeyValue instanceof YAMLKeyValue)) { return; } YAMLKeyValue argumentsKeyValue = YamlHelper.getYamlKeyValue((YAMLKeyValue) serviceKeyValue, "arguments"); // there is no "arguments" key so provide one if(argumentsKeyValue == null) { ServiceActionUtil.ServiceYamlContainer serviceYamlContainer = ServiceActionUtil.ServiceYamlContainer.create((YAMLKeyValue) serviceKeyValue); List<String> yamlMissingArgumentTypes = ServiceActionUtil.getYamlMissingArgumentTypes(project, serviceYamlContainer, false, new ContainerCollectionResolver.LazyServiceCollector(project)); if(yamlMissingArgumentTypes == null) { return; } ServiceActionUtil.fixServiceArgument(project, yamlMissingArgumentTypes, new YamlCreateServiceArgumentsCallback((YAMLKeyValue) serviceKeyValue)); return; } // update service ServiceActionUtil.ServiceYamlContainer serviceYamlContainer = ServiceActionUtil.ServiceYamlContainer.create((YAMLKeyValue) serviceKeyValue); List<String> yamlMissingArgumentTypes = ServiceActionUtil.getYamlMissingArgumentTypes(project, serviceYamlContainer, false, new ContainerCollectionResolver.LazyServiceCollector(project)); if(yamlMissingArgumentTypes == null) { return; } ServiceActionUtil.fixServiceArgument(project, yamlMissingArgumentTypes, new YamlUpdateArgumentServicesCallback( project, argumentsKeyValue, (YAMLKeyValue) serviceKeyValue )); } } }