mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
teach PyFileEvaluator to keep track of declarations; get rid of old code for parsing aug assignments and 'extend' calls
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.extapi.psi.ASTDelegatePsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -18,7 +17,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -324,7 +322,7 @@ public class PyPsiUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void sequenceToList(List<PyExpression> result, PyExpression value) {
|
||||
public static void sequenceToList(List<PyExpression> result, PyExpression value) {
|
||||
value = flattenParens(value);
|
||||
if (value instanceof PySequenceExpression) {
|
||||
result.addAll(ContainerUtil.newArrayList(((PySequenceExpression)value).getElements()));
|
||||
@@ -362,48 +360,6 @@ public class PyPsiUtils {
|
||||
return element.getTextOffset() <= element2.getTextOffset();
|
||||
}
|
||||
|
||||
public static Collection<? extends PyExpression> getAugAssignments(final @NotNull PyFile file, final @NotNull String name) {
|
||||
final List<PyExpression> result = Lists.newArrayList();
|
||||
file.accept(new TopLevelVisitor() {
|
||||
@Override
|
||||
protected void checkAddElement(PsiElement node) {
|
||||
if (node instanceof PyAugAssignmentStatement) {
|
||||
PyAugAssignmentStatement augAss = (PyAugAssignmentStatement)node;
|
||||
if (name.equals(augAss.getTarget().getName())) {
|
||||
sequenceToList(result, augAss.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Collection<? extends PyExpression> getCallArguments(final @NotNull PyFile file,
|
||||
final @NotNull String name,
|
||||
final @NotNull String callName) {
|
||||
final List<PyExpression> result = Lists.newArrayList();
|
||||
file.accept(new TopLevelVisitor() {
|
||||
@Override
|
||||
protected void checkAddElement(PsiElement node) {
|
||||
if (node instanceof PyCallExpression) {
|
||||
PyCallExpression call = (PyCallExpression)node;
|
||||
if (call.getCallee() instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression ref = (PyReferenceExpression)call.getCallee();
|
||||
if (callName.equals(ref.getName())) {
|
||||
PyExpression ex = ref.getQualifier();
|
||||
if (name.equals(ex.getName())) {
|
||||
for (PyExpression expr : call.getArguments()) {
|
||||
sequenceToList(result, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private static abstract class TopLevelVisitor extends PyRecursiveElementVisitor {
|
||||
public void visitPyElement(final PyElement node) {
|
||||
super.visitPyElement(node);
|
||||
|
||||
@@ -14,7 +14,9 @@ import java.util.*;
|
||||
*/
|
||||
public class PyFileEvaluator {
|
||||
private final Map<String, Object> myNamespace = new HashMap<String, Object>();
|
||||
private final Map<String, List<PyExpression>> myDeclarations = new HashMap<String, List<PyExpression>>();
|
||||
private final Set<PyFile> myVisitedFiles;
|
||||
private final Set<String> myDeclarationsToTrack = new HashSet<String>();
|
||||
private String myCurrentFilePath;
|
||||
|
||||
public PyFileEvaluator() {
|
||||
@@ -25,6 +27,10 @@ public class PyFileEvaluator {
|
||||
myVisitedFiles = visitedFiles;
|
||||
}
|
||||
|
||||
public void trackDeclarations(String attrName) {
|
||||
myDeclarationsToTrack.add(attrName);
|
||||
}
|
||||
|
||||
public void evaluate(PyFile file) {
|
||||
VirtualFile vFile = file.getVirtualFile();
|
||||
myCurrentFilePath = vFile != null ? vFile.getPath() : null;
|
||||
@@ -40,17 +46,29 @@ public class PyFileEvaluator {
|
||||
String name = expression.getName();
|
||||
PyExpression value = ((PyTargetExpression)expression).findAssignedValue();
|
||||
myNamespace.put(name, createEvaluator().evaluate(value));
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = new ArrayList<PyExpression>();
|
||||
PyPsiUtils.sequenceToList(declarations, value);
|
||||
myDeclarations.put(name, declarations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
|
||||
PyExpression target = node.getTarget();
|
||||
if (target instanceof PyReferenceExpression && ((PyReferenceExpression)target).getQualifier() == null && target.getName() != null) {
|
||||
Object currentValue = myNamespace.get(target.getName());
|
||||
String name = target.getName();
|
||||
if (target instanceof PyReferenceExpression && ((PyReferenceExpression)target).getQualifier() == null && name != null) {
|
||||
Object currentValue = myNamespace.get(name);
|
||||
if (currentValue != null) {
|
||||
Object rhs = createEvaluator().evaluate(node.getValue());
|
||||
myNamespace.put(target.getName(), PyEvaluator.concatenate(currentValue, rhs));
|
||||
myNamespace.put(name, PyEvaluator.concatenate(currentValue, rhs));
|
||||
}
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = myDeclarations.get(name);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, node.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,12 +88,7 @@ public class PyFileEvaluator {
|
||||
if (qualifier instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
|
||||
if (qualifierRef.getQualifier() == null) {
|
||||
String nameBeingExtended = qualifierRef.getReferencedName();
|
||||
Object value = myNamespace.get(nameBeingExtended);
|
||||
if (value instanceof List) {
|
||||
Object arg = createEvaluator().evaluate(node.getArguments()[0]);
|
||||
myNamespace.put(nameBeingExtended, PyEvaluator.concatenate(value, arg));
|
||||
}
|
||||
processExtendCall(node, qualifierRef.getReferencedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +121,23 @@ public class PyFileEvaluator {
|
||||
});
|
||||
}
|
||||
|
||||
private void processExtendCall(PyCallExpression node, String nameBeingExtended) {
|
||||
PyExpression arg = node.getArguments()[0];
|
||||
|
||||
Object value = myNamespace.get(nameBeingExtended);
|
||||
if (value instanceof List) {
|
||||
Object argValue = createEvaluator().evaluate(arg);
|
||||
myNamespace.put(nameBeingExtended, PyEvaluator.concatenate(value, argValue));
|
||||
}
|
||||
|
||||
if (myDeclarationsToTrack.contains(nameBeingExtended)) {
|
||||
List<PyExpression> declarations = myDeclarations.get(nameBeingExtended);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PyEvaluator createEvaluator() {
|
||||
return new PyPathEvaluator(myCurrentFilePath);
|
||||
}
|
||||
@@ -149,4 +179,10 @@ public class PyFileEvaluator {
|
||||
public Set<PyFile> getVisitedFiles() {
|
||||
return myVisitedFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PyExpression> getDeclarations(String name) {
|
||||
List<PyExpression> expressions = myDeclarations.get(name);
|
||||
return expressions != null ? expressions : Collections.<PyExpression>emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user