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
@@ -1,5 +1,6 @@
package fr.adrienbrault.idea.symfony2plugin.templating.util;

import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import com.intellij.psi.util.PsiTreeUtil;
Expand Down Expand Up @@ -171,11 +172,15 @@ private static Map<String, PsiVariable> collectOnVariableReferences(@NotNull Fun
PsiElement parent = scopeVar.getParent();
if (parent instanceof ArrayAccessExpression) {
// $template['variable'] = $foo
collectedTypes.putAll(getTypesOnArrayIndex((ArrayAccessExpression) parent));
Pair<String, PsiVariable> pair = getTypesOnArrayIndex((ArrayAccessExpression) parent);
if (pair != null) {
collectedTypes.put(pair.getFirst(), pair.getSecond());
}
} else if (parent instanceof AssignmentExpression) {
// array('foo' => $var)
if (((AssignmentExpression) parent).getValue() instanceof ArrayCreationExpression) {
collectedTypes.putAll(getTypesOnArrayHash((ArrayCreationExpression) ((AssignmentExpression) parent).getValue()));
PhpPsiElement value = ((AssignmentExpression) parent).getValue();
if (value instanceof ArrayCreationExpression) {
collectedTypes.putAll(getTypesOnArrayHash((ArrayCreationExpression) value));
}
}
}
Expand All @@ -186,10 +191,8 @@ private static Map<String, PsiVariable> collectOnVariableReferences(@NotNull Fun
/**
* $template['var'] = $foo
*/
private static Map<String, PsiVariable> getTypesOnArrayIndex(ArrayAccessExpression arrayAccessExpression) {

Map<String, PsiVariable> collectedTypes = new HashMap<>();

@Nullable
private static Pair<String, PsiVariable> getTypesOnArrayIndex(@NotNull ArrayAccessExpression arrayAccessExpression) {
ArrayIndex arrayIndex = arrayAccessExpression.getIndex();
if(arrayIndex != null && arrayIndex.getValue() instanceof StringLiteralExpression) {

Expand All @@ -203,28 +206,23 @@ private static Map<String, PsiVariable> getTypesOnArrayIndex(ArrayAccessExpressi
variableTypes.addAll(((PhpTypedElement) arrayValue).getType().getTypes());
}

collectedTypes.put(variableName, new PsiVariable(variableTypes, ((AssignmentExpression) parent).getValue()));

return Pair.create(variableName, new PsiVariable(variableTypes, ((AssignmentExpression) parent).getValue()));
} else {
collectedTypes.put(variableName, new PsiVariable(variableTypes, null));
return Pair.create(variableName, new PsiVariable(variableTypes));
}


}

return collectedTypes;
return null;
}

/**
* array('foo' => $var, 'bar' => $bar)
*/
public static Map<String, PsiVariable> getTypesOnArrayHash(ArrayCreationExpression arrayCreationExpression) {

public static Map<String, PsiVariable> getTypesOnArrayHash(@NotNull ArrayCreationExpression arrayCreationExpression) {
Map<String, PsiVariable> collectedTypes = new HashMap<>();

for(ArrayHashElement arrayHashElement: arrayCreationExpression.getHashElements()) {
if(arrayHashElement.getKey() instanceof StringLiteralExpression) {

String variableName = ((StringLiteralExpression) arrayHashElement.getKey()).getContents();
Set<String> variableTypes = new HashSet<>();

Expand All @@ -233,7 +231,6 @@ public static Map<String, PsiVariable> getTypesOnArrayHash(ArrayCreationExpressi
}

collectedTypes.put(variableName, new PsiVariable(variableTypes, arrayHashElement.getValue()));

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,61 +224,66 @@ private static Map<String, String> getInlineCommentDocsVars(@NotNull PsiElement
return variables;
}

private static Map<String, Set<String>> convertHashMapToTypeSet(Map<String, String> hashMap) {
Map<String, Set<String>> globalVars = new HashMap<>();

for(final Map.Entry<String, String> entry: hashMap.entrySet()) {
globalVars.put(entry.getKey(), new HashSet<>(Collections.singletonList(entry.getValue())));
}

return globalVars;
}

@NotNull
public static Map<String, PsiVariable> collectScopeVariables(@NotNull PsiElement psiElement) {
return collectScopeVariables(psiElement, new HashSet<>());
}

@NotNull
public static Map<String, PsiVariable> collectScopeVariables(@NotNull PsiElement psiElement, @NotNull Set<VirtualFile> visitedFiles) {
Map<String, Set<String>> globalVars = new HashMap<>();
Map<String, PsiVariable> controllerVars = new HashMap<>();

VirtualFile virtualFile = psiElement.getContainingFile().getVirtualFile();
if(visitedFiles.contains(virtualFile)) {
return controllerVars;
return Collections.emptyMap();
}

visitedFiles.add(virtualFile);

Map<String, PsiVariable> controllerVars = new HashMap<>();

TwigFileVariableCollectorParameter collectorParameter = new TwigFileVariableCollectorParameter(psiElement, visitedFiles);
for(TwigFileVariableCollector collector: TWIG_FILE_VARIABLE_COLLECTORS.getExtensions()) {
Map<String, Set<String>> globalVarsScope = new HashMap<>();
collector.collect(collectorParameter, globalVarsScope);

// @TODO: resolve this in change extension point, so that its only possible to provide data and dont give full scope to break / overwrite other variables
globalVarsScope.forEach((s, strings) -> {
globalVars.putIfAbsent(s, new HashSet<>());
globalVars.get(s).addAll(strings);
controllerVars.putIfAbsent(s, new PsiVariable());
controllerVars.get(s).addTypes(strings);
});

// @TODO: provide merge for multiple matches
collector.collectPsiVariables(collectorParameter, controllerVars);
// merging elements
Map<String, PsiVariable> controllerVars1 = new HashMap<>();
collector.collectPsiVariables(collectorParameter, controllerVars1);

controllerVars1.forEach((s, psiVariable) -> {
controllerVars.putIfAbsent(s, new PsiVariable());
controllerVars.get(s).addTypes(psiVariable.getTypes());

PsiElement context = psiVariable.getElement();
if (context != null) {
controllerVars.get(s).addElements(context);
}
});
}

// globals first
globalVars.putAll(convertHashMapToTypeSet(findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.BLOCK_STATEMENT, true)));
globalVars.putAll(convertHashMapToTypeSet(findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.MACRO_STATEMENT, false)));
globalVars.putAll(convertHashMapToTypeSet(findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.FOR_STATEMENT, false)));

for(Map.Entry<String, Set<String>> entry: globalVars.entrySet()) {
Set<String> types = entry.getValue();
Collection<Map<String, String>> vars = Arrays.asList(
findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.BLOCK_STATEMENT, true),
findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.MACRO_STATEMENT, false),
findInlineStatementVariableDocBlock(psiElement, TwigElementTypes.FOR_STATEMENT, false)
);

// collect iterator
types.addAll(collectIteratorReturns(psiElement, entry.getValue()));
for (Map<String, String> entry : vars) {
entry.forEach((s, s2) -> {
controllerVars.putIfAbsent(s, new PsiVariable());
controllerVars.get(s).addType(s2);
});
}

// convert to variable model
controllerVars.put(entry.getKey(), new PsiVariable(types, null));
// collect iterator
for(Map.Entry<String, PsiVariable> entry: controllerVars.entrySet()) {
PsiVariable psiVariable = entry.getValue();
psiVariable.addTypes(collectIteratorReturns(psiElement, psiVariable.getTypes()));
}

// check if we are in "for" scope and resolve types ending with []
Expand Down Expand Up @@ -347,7 +352,7 @@ private static Collection<String> collectForArrayScopeVariablesFoo(@NotNull Proj
return previousElements;
}

private static void collectForArrayScopeVariables(PsiElement psiElement, Map<String, PsiVariable> globalVars) {
private static void collectForArrayScopeVariables(@NotNull PsiElement psiElement, @NotNull Map<String, PsiVariable> globalVars) {
PsiElement twigCompositeElement = PsiTreeUtil.findFirstParent(psiElement, psiElement1 -> {
if (psiElement1 instanceof TwigCompositeElement) {
if (PlatformPatterns.psiElement(TwigElementTypes.FOR_STATEMENT).accepts(psiElement1)) {
Expand Down Expand Up @@ -412,12 +417,12 @@ private static void collectForArrayScopeVariables(PsiElement psiElement, Map<Str
}

// we already have same variable in scope, so merge types
if(globalVars.containsKey(scopeVariable)) {
globalVars.get(scopeVariable).getTypes().addAll(types);
PsiVariable psiVariable = globalVars.get(scopeVariable);
if (psiVariable != null) {
psiVariable.addTypes(types);
} else {
globalVars.put(scopeVariable, new PsiVariable(types));
}

}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,34 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class PsiVariable {
@NotNull
final private Set<String> types;
final private Set<String> types = new HashSet<>();

@Nullable
private PsiElement psiElement;
@NotNull
final private Collection<PsiElement> psiElements = new HashSet<>();

public PsiVariable(@NotNull Set<String> types, @Nullable PsiElement psiElement) {
this.types = types;
this.psiElement = psiElement;
this.types.addAll(types);
this.psiElements.add(psiElement);
}

public PsiVariable(@NotNull Set<String> types) {
this.types = types;
this.types.addAll(types);
}

public PsiVariable(@NotNull String type) {
this.types = Collections.singleton(type);
this.types.add(type);
}

public PsiVariable() {
}

@NotNull
Expand All @@ -37,6 +41,22 @@ public Set<String> getTypes() {

@Nullable
public PsiElement getElement() {
return psiElement;
if (psiElements.size() > 0) {
return psiElements.iterator().next();
}

return null;
}

public void addElements(@NotNull PsiElement psiElement) {
this.psiElements.add(psiElement);
}

public void addTypes(@NotNull Collection<String> types) {
this.types.addAll(types);
}

public void addType(@NotNull String type) {
this.types.add(type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;

/**
* @author Daniel Espendiller <daniel@espendiller.net>
Expand All @@ -23,17 +20,21 @@ public class ServiceContainerGlobalVariableCollector implements TwigFileVariable

@Override
public void collect(@NotNull TwigFileVariableCollectorParameter parameter, @NotNull Map<String, Set<String>> variables) {
Map<String, Set<String>> map = new HashMap<>();

TwigGlobalsServiceParser twigPathServiceParser = ServiceXmlParserFactory.getInstance(parameter.getProject(), TwigGlobalsServiceParser.class);
for(Map.Entry<String, TwigGlobalVariable> globalVariableEntry: twigPathServiceParser.getTwigGlobals().entrySet()) {
if(globalVariableEntry.getValue().getTwigGlobalEnum() == TwigGlobalEnum.SERVICE) {
String serviceName = globalVariableEntry.getValue().getValue();
PhpClass phpClass = ServiceUtil.getServiceClass(parameter.getProject(), serviceName);
if(phpClass != null) {
variables.put(globalVariableEntry.getKey(), new HashSet<>(Collections.singletonList(
StringUtils.stripStart(phpClass.getFQN(), "\\")
)));
String key = globalVariableEntry.getKey();
map.putIfAbsent(key, new HashSet<>());
map.get(key).add("\\" + StringUtils.stripStart(phpClass.getFQN(), "\\"));
}
}
}

variables.putAll(map);
}
}