Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,16 @@ public void visitElement(PsiElement element) {
PsiElement serviceKeyValue = yamlCompoundValue.getParent();
if(serviceKeyValue instanceof YAMLKeyValue) {
Set<String> tags = YamlHelper.collectServiceTags((YAMLKeyValue) serviceKeyValue);
if(tags != null && tags.size() > 0) {
if(tags.size() > 0) {
registerTaggedProblems(element, tags, text, holder, this.lazyServiceCollector);
}
}

}
}

}


super.visitElement(element);
}

}

private void registerTaggedProblems(@NotNull PsiElement source, @NotNull Set<String> tags, @NotNull String serviceClass, @NotNull ProblemsHolder holder, @NotNull ContainerCollectionResolver.LazyServiceCollector lazyServiceCollector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.jetbrains.php.lang.psi.elements.Parameter;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import fr.adrienbrault.idea.symfony2plugin.config.xml.XmlHelper;
import fr.adrienbrault.idea.symfony2plugin.config.yaml.YamlElementPatternHelper;
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.AttributeValueInterface;
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.XmlTagAttributeValue;
import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.YamlKeyValueAttributeValue;
Expand All @@ -29,10 +30,7 @@
import fr.adrienbrault.idea.symfony2plugin.dic.container.visitor.ServiceConsumer;
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.ContainerIdUsagesStubIndex;
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import fr.adrienbrault.idea.symfony2plugin.util.TimeSecondModificationTracker;
import fr.adrienbrault.idea.symfony2plugin.util.*;
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
import fr.adrienbrault.idea.symfony2plugin.util.psi.PsiElementAssertUtil;
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
Expand All @@ -43,6 +41,7 @@
import org.jetbrains.yaml.psi.*;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -421,18 +420,46 @@ public static Parameter getYamlNamedArgument(@NotNull PsiElement psiElement, @No
*/
public static void visitNamedArguments(@NotNull PsiFile psiFile, @NotNull Consumer<Parameter> processor) {
if (psiFile instanceof YAMLFile) {
Collection<Parameter> parameters = new HashSet<>();

// direct service definition
for (PhpClass phpClass : YamlHelper.getPhpClassesInYamlFile((YAMLFile) psiFile, new ContainerCollectionResolver.LazyServiceCollector(psiFile.getProject()))) {
Method constructor = phpClass.getConstructor();
if (constructor == null) {
continue;
}

Arrays.stream(constructor.getParameters()).forEach(processor::consume);
parameters.addAll(Arrays.asList(constructor.getParameters()));
}

for (YAMLKeyValue taggedService : YamlHelper.getTaggedServices((YAMLFile) psiFile, "controller.service_arguments")) {
PsiElement key = taggedService.getKey();
if (key == null) {
continue;
}

String keyText = key.getText();
if (StringUtils.isBlank(keyText)) {
continue;
}

// App\Controller\ => \App\Controller
String namespace = StringUtils.strip(keyText, "\\");
for (PhpClass phpClass : PhpIndexUtil.getPhpClassInsideNamespace(psiFile.getProject(), "\\" + namespace)) {
// find all parameters on public methods; this are possible actions

// maybe filter actions and public methods in a suitable way?
phpClass.getMethods().stream()
.filter(method -> method.getAccess().isPublic() && !method.getName().startsWith("set"))
.forEach(method -> Collections.addAll(parameters, method.getParameters()));
}
}

parameters.forEach(processor::consume);
}
}

/**
/*
* Symfony 3.3: "class" is optional; use service name for its it
*
* Foo\Bar:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,21 +222,20 @@ public static void attachFormAliasesCompletions(@NotNull PhpClass phpClass, @Not
*/
@NotNull
public static Map<String, Set<String>> getTags(@NotNull YAMLFile yamlFile) {

Map<String, Set<String>> map = new HashMap<>();

for(YAMLKeyValue yamlServiceKeyValue : YamlHelper.getQualifiedKeyValuesInFile(yamlFile, "services")) {
String serviceName = yamlServiceKeyValue.getName();
Set<String> serviceTagMap = YamlHelper.collectServiceTags(yamlServiceKeyValue);
if(serviceTagMap != null && serviceTagMap.size() > 0) {
if(serviceTagMap.size() > 0) {
map.put(serviceName, serviceTagMap);
}
}

return map;
}

public static Map<String, Set<String>> getTags(XmlFile psiFile) {

public static Map<String, Set<String>> getTags(@NotNull XmlFile psiFile) {
Map<String, Set<String>> map = new HashMap<>();

XmlDocumentImpl document = PsiTreeUtil.getChildOfType(psiFile, XmlDocumentImpl.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private static Pair<PhpClass, Set<String>> invoke(@NotNull Project project, @Not
Set<String> phpClassServiceTags = ServiceUtil.getPhpClassServiceTags(resolvedClassDefinition);

Set<String> strings = YamlHelper.collectServiceTags(serviceKeyValue);
if(strings != null && strings.size() > 0) {
if(strings.size() > 0) {
for (String s : strings) {
if(phpClassServiceTags.contains(s)) {
phpClassServiceTags.remove(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,23 +625,21 @@ public static YAMLKeyValue findServiceInContext(@NotNull PsiElement psiElement)
* @param yamlKeyValue the service key value to find the "tags" key on
* @return tag names
*/
@Nullable
@NotNull
public static Set<String> collectServiceTags(@NotNull YAMLKeyValue yamlKeyValue) {

YAMLKeyValue tagsKeyValue = YamlHelper.getYamlKeyValue(yamlKeyValue, "tags");
if(tagsKeyValue == null) {
return null;
return Collections.emptySet();
}

PsiElement tagsCompound = tagsKeyValue.getValue();
if(!(tagsCompound instanceof YAMLSequence)) {
return null;
return Collections.emptySet();
}

Set<String> tags = new HashSet<>();

for (YAMLSequenceItem yamlSequenceItem : ((YAMLSequence) tagsCompound).getItems()) {

YAMLValue value = yamlSequenceItem.getValue();
if(value instanceof YAMLMapping) {
// tags:
Expand All @@ -664,6 +662,26 @@ public static Set<String> collectServiceTags(@NotNull YAMLKeyValue yamlKeyValue)
return tags;
}

/**
* acme_demo.form.type.gender:
* class: espend\Form\TypeBundle\Form\FooType
* tags:
* - { name: foo }
*/
@NotNull
public static Collection<YAMLKeyValue> getTaggedServices(@NotNull YAMLFile yamlFile, @NotNull String tag) {
Collection<YAMLKeyValue> yamlKeyValues = new HashSet<>();

for (YAMLKeyValue yamlServiceKeyValue : YamlHelper.getQualifiedKeyValuesInFile(yamlFile, "services")) {
Set<String> serviceTagMap = YamlHelper.collectServiceTags(yamlServiceKeyValue);
if (serviceTagMap.contains(tag)) {
yamlKeyValues.add(yamlServiceKeyValue);
}
}

return yamlKeyValues;
}

/**
* TODO: use visitor pattern for all tags, we are using them to often
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.php.lang.psi.elements.Parameter;
import fr.adrienbrault.idea.symfony2plugin.dic.container.ServiceInterface;
import fr.adrienbrault.idea.symfony2plugin.dic.container.ServiceSerializable;
import fr.adrienbrault.idea.symfony2plugin.dic.container.dict.ServiceTypeHint;
import fr.adrienbrault.idea.symfony2plugin.dic.container.util.ServiceContainerUtil;
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.yaml.psi.YAMLFile;
import org.jetbrains.yaml.psi.YAMLScalar;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/**
Expand Down Expand Up @@ -299,6 +303,26 @@ public void testGetXmlCallTypeHint() {
assertEquals("setFoo", typeHint.getMethod().getName());
}

public void testVisitNamedArguments() {
PsiFile psiFile = myFixture.configureByText("test.yml", "" +
"services:\n" +
" NamedArgument\\Foobar:\n" +
" arguments: []\n" +
"" +
" App\\Controller\\:\n" +
" resource: '../src/Controller'\n" +
" tags: ['controller.service_arguments']\n"
);

Collection<String> arguments = new HashSet<>();
ServiceContainerUtil.visitNamedArguments(psiFile, parameter -> arguments.add(parameter.getName()));

assertTrue(arguments.contains("foobar"));

assertTrue(arguments.contains("foobarString"));
assertFalse(arguments.contains("private"));
}

private static class MyStringServiceInterfaceCondition implements Condition<ServiceInterface> {

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,18 @@ public function setFoo($foo, Foobar $foobar)
{
}
}
}

namespace App\Controller
{
class FoobarController
{
public function fooAction($fooEntity, string $foobarString)
{
}

private function fooPrivate($private)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.php.lang.psi.elements.Parameter;
Expand Down Expand Up @@ -192,14 +193,15 @@ public void testCollectServiceTagsForSymfony33TagsShortcut() {
public void testCollectServiceTagsForSymfony33TagsShortcutInline() {
YAMLKeyValue fromText = YamlPsiElementFactory.createFromText(getProject(), YAMLKeyValue.class, "" +
"foo:\n" +
" tags: [routing.loader_tags_3, routing.loader_tags_4]\n"
" tags: [routing.loader_tags_3, routing.loader_tags_4, 'routing.loader_tags_5']\n"
);

assertNotNull(fromText);
Set<String> collection = YamlHelper.collectServiceTags(fromText);

assertContainsElements(collection, "routing.loader_tags_3");
assertContainsElements(collection, "routing.loader_tags_4");
assertContainsElements(collection, "routing.loader_tags_5");
}

/**
Expand Down Expand Up @@ -551,6 +553,25 @@ public void testGetServiceDefinitionClassFromTagMethod() {
assertEquals("ClassName\\Foo", YamlHelper.getServiceDefinitionClassFromTagMethod(psiElement));
}

public void testGetTaggedServices() {
PsiFile psiFile = myFixture.configureByText(YAMLFileType.YML, "" +
"services:\n" +
" foobar:\n" +
" class: ClassName\\Foo\n" +
" tags:\n" +
" - { name: crossHint.test_222 }\n" +
" foobar2:\n" +
" class: ClassName\\Foo\n" +
" tags: [ 'test.11' ]\n"
);

Collection<YAMLKeyValue> taggedServices1 = YamlHelper.getTaggedServices((YAMLFile) psiFile, "crossHint.test_222");
assertTrue(taggedServices1.stream().anyMatch(yamlKeyValue -> "foobar".equals(yamlKeyValue.getKey().getText())));

Collection<YAMLKeyValue> taggedServices2 = YamlHelper.getTaggedServices((YAMLFile) psiFile, "test.11");
assertTrue(taggedServices2.stream().anyMatch(yamlKeyValue -> "foobar2".equals(yamlKeyValue.getKey().getText())));
}

private int getIndentForTextContent(@NotNull String content) {
return YamlHelper.getIndentSpaceForFile((YAMLFile) YamlPsiElementFactory.createDummyFile(
getProject(),
Expand Down