mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-13180 Pycharm 3.4: Right mouse click on selected text inside unicode string hangs out IDE interface for 20-30 seconds:
Performance fix #3
This commit is contained in:
@@ -34,7 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public class PyMagicLiteralRenameHandler implements RenameHandler {
|
||||
@Override
|
||||
public boolean isAvailableOnDataContext(DataContext dataContext) {
|
||||
public boolean isAvailableOnDataContext(final DataContext dataContext) {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
if (editor == null) {
|
||||
return false;
|
||||
@@ -47,11 +47,7 @@ public class PyMagicLiteralRenameHandler implements RenameHandler {
|
||||
|
||||
final PsiElement element = getElement(file, editor);
|
||||
|
||||
if (element == null || !PyMagicLiteralTools.isMagicLiteral(element)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !((element == null) || !PyMagicLiteralTools.isMagicLiteral(element));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author yole
|
||||
*/
|
||||
public class PyBlockEvaluator {
|
||||
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;
|
||||
private Object myReturnValue;
|
||||
private boolean myEvaluateCollectionItems = true;
|
||||
|
||||
public PyBlockEvaluator() {
|
||||
myVisitedFiles = new HashSet<PyFile>();
|
||||
}
|
||||
|
||||
public PyBlockEvaluator(Set<PyFile> visitedFiles) {
|
||||
myVisitedFiles = visitedFiles;
|
||||
}
|
||||
|
||||
public void trackDeclarations(String attrName) {
|
||||
myDeclarationsToTrack.add(attrName);
|
||||
}
|
||||
|
||||
public void evaluate(PyElement element) {
|
||||
VirtualFile vFile = element.getContainingFile().getVirtualFile();
|
||||
myCurrentFilePath = vFile != null ? vFile.getPath() : null;
|
||||
if (myVisitedFiles.contains(element)) {
|
||||
return;
|
||||
}
|
||||
myVisitedFiles.add((PyFile)element.getContainingFile());
|
||||
PyElement statementContainer = element instanceof PyFunction ? ((PyFunction) element).getStatementList() : element;
|
||||
if (statementContainer == null) {
|
||||
return;
|
||||
}
|
||||
statementContainer.acceptChildren(new PyElementVisitor() {
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
PyExpression expression = node.getLeftHandSideExpression();
|
||||
if (expression instanceof PyTargetExpression) {
|
||||
String name = expression.getName();
|
||||
PyExpression value = ((PyTargetExpression)expression).findAssignedValue();
|
||||
myNamespace.put(name, prepareEvaluator().evaluate(value));
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = new ArrayList<PyExpression>();
|
||||
PyPsiUtils.sequenceToList(declarations, value);
|
||||
myDeclarations.put(name, declarations);
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PySubscriptionExpression) {
|
||||
PyExpression operand = ((PySubscriptionExpression)expression).getOperand();
|
||||
PyExpression indexExpression = ((PySubscriptionExpression)expression).getIndexExpression();
|
||||
if (operand instanceof PyReferenceExpression && ((PyReferenceExpression)operand).getQualifier() == null) {
|
||||
Object currentValue = myNamespace.get(((PyReferenceExpression)operand).getReferencedName());
|
||||
if (currentValue instanceof Map) {
|
||||
Object mapKey = prepareEvaluator().evaluate(indexExpression);
|
||||
if (mapKey != null) {
|
||||
Object value = myEvaluateCollectionItems ? prepareEvaluator().evaluate(node.getAssignedValue()) : node.getAssignedValue();
|
||||
((Map)currentValue).put(mapKey, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
|
||||
PyExpression target = node.getTarget();
|
||||
String name = target.getName();
|
||||
if (target instanceof PyReferenceExpression && !((PyReferenceExpression)target).isQualified() && name != null) {
|
||||
Object currentValue = myNamespace.get(name);
|
||||
if (currentValue != null) {
|
||||
Object rhs = prepareEvaluator().evaluate(node.getValue());
|
||||
myNamespace.put(name, prepareEvaluator().concatenate(currentValue, rhs));
|
||||
}
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = myDeclarations.get(name);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, node.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyExpressionStatement(PyExpressionStatement node) {
|
||||
node.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
PyExpression callee = node.getCallee();
|
||||
if (callee instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression calleeRef = (PyReferenceExpression)callee;
|
||||
PyExpression qualifier = calleeRef.getQualifier();
|
||||
if (qualifier instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
|
||||
if (!qualifierRef.isQualified()) {
|
||||
if (PyNames.EXTEND.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
|
||||
processExtendCall(node, qualifierRef.getReferencedName());
|
||||
}
|
||||
else if (PyNames.UPDATE.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
|
||||
processUpdateCall(node, qualifierRef.getReferencedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFromImportStatement(PyFromImportStatement node) {
|
||||
if (node.isFromFuture()) return;
|
||||
PsiElement source = PyUtil.turnDirIntoInit(node.resolveImportSource());
|
||||
if (source instanceof PyFile) {
|
||||
PyBlockEvaluator importEvaluator = new PyBlockEvaluator(myVisitedFiles);
|
||||
importEvaluator.myDeclarationsToTrack.addAll(myDeclarationsToTrack);
|
||||
importEvaluator.evaluate((PyFile)source);
|
||||
if (node.isStarImport()) {
|
||||
// TODO honor __all__ here
|
||||
myNamespace.putAll(importEvaluator.myNamespace);
|
||||
myDeclarations.putAll(importEvaluator.myDeclarations);
|
||||
}
|
||||
else {
|
||||
for (final PyImportElement element : node.getImportElements()) {
|
||||
final String nameOfVarInOurModule = element.getVisibleName();
|
||||
final QualifiedName nameOfVarInExternalModule = element.getImportedQName();
|
||||
if ((nameOfVarInOurModule == null) || (nameOfVarInExternalModule == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Object value = importEvaluator.myNamespace.get(nameOfVarInExternalModule.toString());
|
||||
myNamespace.put(nameOfVarInOurModule, value);
|
||||
final List<PyExpression> declarations = importEvaluator.getDeclarations(nameOfVarInOurModule);
|
||||
if (myDeclarations.containsKey(nameOfVarInOurModule)) {
|
||||
myDeclarations.get(nameOfVarInOurModule).addAll(declarations);
|
||||
}
|
||||
else {
|
||||
myDeclarations.put(nameOfVarInOurModule, declarations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyIfStatement(PyIfStatement node) {
|
||||
PyStatementList list = node.getIfPart().getStatementList();
|
||||
if (list != null) {
|
||||
list.acceptChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyReturnStatement(PyReturnStatement node) {
|
||||
myReturnValue = prepareEvaluator().evaluate(node.getExpression());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void processExtendCall(PyCallExpression node, String nameBeingExtended) {
|
||||
PyExpression arg = node.getArguments()[0];
|
||||
|
||||
Object value = myNamespace.get(nameBeingExtended);
|
||||
if (value instanceof List) {
|
||||
Object argValue = prepareEvaluator().evaluate(arg);
|
||||
myNamespace.put(nameBeingExtended, prepareEvaluator().concatenate(value, argValue));
|
||||
}
|
||||
|
||||
if (myDeclarationsToTrack.contains(nameBeingExtended)) {
|
||||
List<PyExpression> declarations = myDeclarations.get(nameBeingExtended);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processUpdateCall(PyCallExpression node, String name) {
|
||||
Object value = myNamespace.get(name);
|
||||
if (value instanceof Map) {
|
||||
Object argValue = prepareEvaluator().evaluate(node.getArguments()[0]);
|
||||
if (argValue instanceof Map) {
|
||||
((Map)value).putAll((Map)argValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PyEvaluator prepareEvaluator() {
|
||||
PyEvaluator evaluator = createEvaluator();
|
||||
evaluator.setNamespace(myNamespace);
|
||||
evaluator.setEvaluateCollectionItems(myEvaluateCollectionItems);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
protected PyEvaluator createEvaluator() {
|
||||
return new PyPathEvaluator(myCurrentFilePath);
|
||||
}
|
||||
|
||||
public Object getValue(String name) {
|
||||
return myNamespace.get(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getValueAsString(String name) {
|
||||
Object value = myNamespace.get(name);
|
||||
return value instanceof String ? (String) value : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List getValueAsList(String name) {
|
||||
Object value = myNamespace.get(name);
|
||||
return value instanceof List ? (List) value : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getValueAsStringList(String name) {
|
||||
Object value = myNamespace.get(name);
|
||||
if (value instanceof List) {
|
||||
List valueList = (List) value;
|
||||
for (Object o : valueList) {
|
||||
if (o != null && !(o instanceof String)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
return (List<String>) value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Collections.singletonList((String) value);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public Object getReturnValue() {
|
||||
return myReturnValue;
|
||||
}
|
||||
|
||||
public void setEvaluateCollectionItems(boolean evaluateCollectionItems) {
|
||||
myEvaluateCollectionItems = evaluateCollectionItems;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.psi.impl.blockEvaluator;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyEvaluator;
|
||||
import com.jetbrains.python.psi.impl.PyPathEvaluator;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class PyBlockEvaluator {
|
||||
@NotNull
|
||||
private final PyEvaluationResult myEvaluationResult = new PyEvaluationResult();
|
||||
@NotNull
|
||||
private final PyEvaluationContext myContext;
|
||||
private final Set<PyFile> myVisitedFiles;
|
||||
private final Set<String> myDeclarationsToTrack = new HashSet<String>();
|
||||
private String myCurrentFilePath;
|
||||
private Object myReturnValue;
|
||||
private boolean myEvaluateCollectionItems = true;
|
||||
|
||||
/**
|
||||
* @param evaluationContext context, obtained via {@link #getContext()}. Pass it here to enable cache. See {@link com.jetbrains.python.psi.impl.blockEvaluator.PyEvaluationContext}
|
||||
* for more info
|
||||
* @see com.jetbrains.python.psi.impl.blockEvaluator.PyEvaluationContext
|
||||
*/
|
||||
public PyBlockEvaluator(@NotNull final PyEvaluationContext evaluationContext) {
|
||||
this(Sets.<PyFile>newHashSet(), evaluationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create evaluator with out of cache context
|
||||
*/
|
||||
public PyBlockEvaluator() {
|
||||
this(new PyEvaluationContext());
|
||||
}
|
||||
|
||||
private PyBlockEvaluator(@NotNull final Set<PyFile> visitedFiles, @NotNull final PyEvaluationContext evaluationContext) {
|
||||
myVisitedFiles = visitedFiles;
|
||||
myContext = evaluationContext;
|
||||
}
|
||||
|
||||
public void trackDeclarations(String attrName) {
|
||||
myDeclarationsToTrack.add(attrName);
|
||||
}
|
||||
|
||||
public void evaluate(PyElement element) {
|
||||
VirtualFile vFile = element.getContainingFile().getVirtualFile();
|
||||
myCurrentFilePath = vFile != null ? vFile.getPath() : null;
|
||||
if (myVisitedFiles.contains(element)) {
|
||||
return;
|
||||
}
|
||||
myVisitedFiles.add((PyFile)element.getContainingFile());
|
||||
PyElement statementContainer = element instanceof PyFunction ? ((PyFunction)element).getStatementList() : element;
|
||||
if (statementContainer == null) {
|
||||
return;
|
||||
}
|
||||
statementContainer.acceptChildren(new MyPyElementVisitor());
|
||||
}
|
||||
|
||||
private void processExtendCall(PyCallExpression node, String nameBeingExtended) {
|
||||
PyExpression arg = node.getArguments()[0];
|
||||
|
||||
Object value = myEvaluationResult.myNamespace.get(nameBeingExtended);
|
||||
if (value instanceof List) {
|
||||
Object argValue = prepareEvaluator().evaluate(arg);
|
||||
myEvaluationResult.myNamespace.put(nameBeingExtended, prepareEvaluator().concatenate(value, argValue));
|
||||
}
|
||||
|
||||
if (myDeclarationsToTrack.contains(nameBeingExtended)) {
|
||||
List<PyExpression> declarations = myEvaluationResult.myDeclarations.get(nameBeingExtended);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processUpdateCall(PyCallExpression node, String name) {
|
||||
Object value = myEvaluationResult.myNamespace.get(name);
|
||||
if (value instanceof Map) {
|
||||
Object argValue = prepareEvaluator().evaluate(node.getArguments()[0]);
|
||||
if (argValue instanceof Map) {
|
||||
((Map)value).putAll((Map)argValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PyEvaluator prepareEvaluator() {
|
||||
PyEvaluator evaluator = createEvaluator();
|
||||
evaluator.setNamespace(myEvaluationResult.myNamespace);
|
||||
evaluator.setEvaluateCollectionItems(myEvaluateCollectionItems);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
protected PyEvaluator createEvaluator() {
|
||||
return new PyPathEvaluator(myCurrentFilePath);
|
||||
}
|
||||
|
||||
public Object getValue(String name) {
|
||||
return myEvaluationResult.myNamespace.get(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getValueAsString(String name) {
|
||||
Object value = myEvaluationResult.myNamespace.get(name);
|
||||
return value instanceof String ? (String)value : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List getValueAsList(String name) {
|
||||
Object value = myEvaluationResult.myNamespace.get(name);
|
||||
return value instanceof List ? (List)value : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getValueAsStringList(String name) {
|
||||
Object value = myEvaluationResult.myNamespace.get(name);
|
||||
if (value instanceof List) {
|
||||
List valueList = (List)value;
|
||||
for (Object o : valueList) {
|
||||
if (o != null && !(o instanceof String)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
return (List<String>)value;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return Collections.singletonList((String)value);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public Set<PyFile> getVisitedFiles() {
|
||||
return myVisitedFiles;
|
||||
}
|
||||
|
||||
|
||||
public Object getReturnValue() {
|
||||
return myReturnValue;
|
||||
}
|
||||
|
||||
public void setEvaluateCollectionItems(boolean evaluateCollectionItems) {
|
||||
myEvaluateCollectionItems = evaluateCollectionItems;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<PyExpression> getDeclarations(@NotNull final String name) {
|
||||
return myEvaluationResult.getDeclarations(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return so-called context. You may pass it to any instance of {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator}
|
||||
* to make instances share their cache
|
||||
*/
|
||||
@NotNull
|
||||
public PyEvaluationContext getContext() {
|
||||
return myContext;
|
||||
}
|
||||
|
||||
private class MyPyElementVisitor extends PyElementVisitor {
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
PyExpression expression = node.getLeftHandSideExpression();
|
||||
if (expression instanceof PyTargetExpression) {
|
||||
String name = expression.getName();
|
||||
PyExpression value = ((PyTargetExpression)expression).findAssignedValue();
|
||||
myEvaluationResult.myNamespace.put(name, prepareEvaluator().evaluate(value));
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = new ArrayList<PyExpression>();
|
||||
PyPsiUtils.sequenceToList(declarations, value);
|
||||
myEvaluationResult.myDeclarations.put(name, declarations);
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PySubscriptionExpression) {
|
||||
PyExpression operand = ((PySubscriptionExpression)expression).getOperand();
|
||||
PyExpression indexExpression = ((PySubscriptionExpression)expression).getIndexExpression();
|
||||
if (operand instanceof PyReferenceExpression && ((PyReferenceExpression)operand).getQualifier() == null) {
|
||||
Object currentValue = myEvaluationResult.myNamespace.get(((PyReferenceExpression)operand).getReferencedName());
|
||||
if (currentValue instanceof Map) {
|
||||
Object mapKey = prepareEvaluator().evaluate(indexExpression);
|
||||
if (mapKey != null) {
|
||||
Object value = myEvaluateCollectionItems ? prepareEvaluator().evaluate(node.getAssignedValue()) : node.getAssignedValue();
|
||||
((Map)currentValue).put(mapKey, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAugAssignmentStatement(PyAugAssignmentStatement node) {
|
||||
PyExpression target = node.getTarget();
|
||||
String name = target.getName();
|
||||
if (target instanceof PyReferenceExpression && !((PyReferenceExpression)target).isQualified() && name != null) {
|
||||
Object currentValue = myEvaluationResult.myNamespace.get(name);
|
||||
if (currentValue != null) {
|
||||
Object rhs = prepareEvaluator().evaluate(node.getValue());
|
||||
myEvaluationResult.myNamespace.put(name, prepareEvaluator().concatenate(currentValue, rhs));
|
||||
}
|
||||
if (myDeclarationsToTrack.contains(name)) {
|
||||
List<PyExpression> declarations = myEvaluationResult.myDeclarations.get(name);
|
||||
if (declarations != null) {
|
||||
PyPsiUtils.sequenceToList(declarations, node.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyExpressionStatement(PyExpressionStatement node) {
|
||||
node.getExpression().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
PyExpression callee = node.getCallee();
|
||||
if (callee instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression calleeRef = (PyReferenceExpression)callee;
|
||||
PyExpression qualifier = calleeRef.getQualifier();
|
||||
if (qualifier instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression qualifierRef = (PyReferenceExpression)qualifier;
|
||||
if (!qualifierRef.isQualified()) {
|
||||
if (PyNames.EXTEND.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
|
||||
processExtendCall(node, qualifierRef.getReferencedName());
|
||||
}
|
||||
else if (PyNames.UPDATE.equals(calleeRef.getReferencedName()) && node.getArguments().length == 1) {
|
||||
processUpdateCall(node, qualifierRef.getReferencedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFromImportStatement(final PyFromImportStatement node) {
|
||||
if (node.isFromFuture()) return;
|
||||
final PsiElement source = PyUtil.turnDirIntoInit(node.resolveImportSource());
|
||||
if (source instanceof PyFile) {
|
||||
final PyFile pyFile = (PyFile)source;
|
||||
PyEvaluationResult newlyEvaluatedResult = myContext.getCachedResult(pyFile);
|
||||
|
||||
if (newlyEvaluatedResult == null) {
|
||||
final PyBlockEvaluator importEvaluator = new PyBlockEvaluator(myVisitedFiles, myContext);
|
||||
importEvaluator.myDeclarationsToTrack.addAll(myDeclarationsToTrack);
|
||||
importEvaluator.evaluate(pyFile);
|
||||
newlyEvaluatedResult = importEvaluator.myEvaluationResult;
|
||||
myContext.cache(pyFile, newlyEvaluatedResult);
|
||||
}
|
||||
|
||||
if (node.isStarImport()) {
|
||||
// TODO honor __all__ here
|
||||
myEvaluationResult.myNamespace.putAll(newlyEvaluatedResult.myNamespace);
|
||||
myEvaluationResult.myDeclarations.putAll(newlyEvaluatedResult.myDeclarations);
|
||||
}
|
||||
else {
|
||||
for (final PyImportElement element : node.getImportElements()) {
|
||||
final String nameOfVarInOurModule = element.getVisibleName();
|
||||
final QualifiedName nameOfVarInExternalModule = element.getImportedQName();
|
||||
if ((nameOfVarInOurModule == null) || (nameOfVarInExternalModule == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Object value = newlyEvaluatedResult.myNamespace.get(nameOfVarInExternalModule.toString());
|
||||
myEvaluationResult.myNamespace.put(nameOfVarInOurModule, value);
|
||||
final List<PyExpression> declarations = newlyEvaluatedResult.getDeclarations(nameOfVarInOurModule);
|
||||
if (myEvaluationResult.myDeclarations.containsKey(nameOfVarInOurModule)) {
|
||||
myEvaluationResult.myDeclarations.get(nameOfVarInOurModule).addAll(declarations);
|
||||
}
|
||||
else {
|
||||
myEvaluationResult.myDeclarations.put(nameOfVarInOurModule, declarations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyIfStatement(PyIfStatement node) {
|
||||
PyStatementList list = node.getIfPart().getStatementList();
|
||||
if (list != null) {
|
||||
list.acceptChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyReturnStatement(PyReturnStatement node) {
|
||||
myReturnValue = prepareEvaluator().evaluate(node.getExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.jetbrains.python.psi.impl.blockEvaluator;
|
||||
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Cache for {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator}.
|
||||
* You may obtain one via {@link PyBlockEvaluator#getContext()} and pass to ctor:
|
||||
* {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator#PyBlockEvaluator(PyEvaluationContext)} to enable cache
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
public class PyEvaluationContext {
|
||||
@NotNull
|
||||
private final Map<PyFile, PyEvaluationResult> myResultMap = new HashMap<PyFile, PyEvaluationResult>();
|
||||
|
||||
PyEvaluationContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get evaluation result by file
|
||||
* @param file file
|
||||
* @return eval result
|
||||
*/
|
||||
@Nullable
|
||||
PyEvaluationResult getCachedResult(@NotNull final PyFile file) {
|
||||
return myResultMap.get(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store evaluation result by file
|
||||
* @param file file
|
||||
* @param result evaluation result
|
||||
*/
|
||||
void cache(@NotNull final PyFile file, @NotNull final PyEvaluationResult result) {
|
||||
myResultMap.put(file, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.jetbrains.python.psi.impl.blockEvaluator;
|
||||
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
@SuppressWarnings("PackageVisibleField") // Package-only class
|
||||
class PyEvaluationResult {
|
||||
@NotNull
|
||||
final Map<String, Object> myNamespace = new HashMap<String, Object>();
|
||||
@NotNull
|
||||
final Map<String, List<PyExpression>> myDeclarations = new HashMap<String, List<PyExpression>>();
|
||||
|
||||
@NotNull
|
||||
List<PyExpression> getDeclarations(@NotNull final String name) {
|
||||
final List<PyExpression> expressions = myDeclarations.get(name);
|
||||
return (expressions != null) ? expressions : Collections.<PyExpression>emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Engine to evaluate block of python text.
|
||||
* Use {@link com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator} as entry point.
|
||||
*
|
||||
* @author Ilya.Kazakevich
|
||||
*/
|
||||
package com.jetbrains.python.psi.impl.blockEvaluator;
|
||||
@@ -21,7 +21,7 @@ import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import com.jetbrains.python.psi.PyStringLiteralExpression;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.impl.PyBlockEvaluator;
|
||||
import com.jetbrains.python.psi.impl.blockEvaluator.PyBlockEvaluator;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
Reference in New Issue
Block a user