Scope implementation for Python

This commit is contained in:
Oleg Shpynov
2010-01-25 19:40:33 +03:00
parent d084ece527
commit de1778309a
15 changed files with 153 additions and 16 deletions
@@ -3,7 +3,6 @@ package com.jetbrains.python.codeInsight.controlflow;
import com.intellij.codeInsight.controlflow.ControlFlowBuilder;
import com.intellij.codeInsight.controlflow.ControlFlow;
import com.intellij.codeInsight.controlflow.Instruction;
import com.intellij.codeInsight.controlflow.impl.ControlFlowImpl;
import com.intellij.codeInsight.controlflow.impl.InstructionImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
@@ -26,7 +25,7 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
//// Control flow builder staff
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ControlFlow buildControlFlow(@NotNull final ControlFlowOwner owner) {
public ControlFlow buildControlFlow(@NotNull final ScopeOwner owner) {
return myBuilder.build(this, owner);
}
@@ -1,11 +1,13 @@
package com.jetbrains.python.codeInsight.controlflow;
import com.intellij.codeInsight.controlflow.ControlFlow;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.psi.PyElement;
/**
* @author oleg
*/
public interface ControlFlowOwner extends PyElement {
public interface ScopeOwner extends PyElement {
ControlFlow getControlFlow();
Scope getScope();
}
@@ -6,6 +6,9 @@ import com.intellij.codeInsight.dataflow.DfaInstance;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.codeInsight.controlflow.WriteInstruction;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
import com.jetbrains.python.codeInsight.dataflow.scope.impl.ScopeVariableImpl;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@@ -5,6 +5,8 @@ import com.intellij.codeInsight.dataflow.Semilattice;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.HashSet;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
import com.jetbrains.python.codeInsight.dataflow.scope.impl.ScopeVariableImpl;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -0,0 +1,24 @@
package com.jetbrains.python.codeInsight.dataflow.scope;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* @author oleg
*/
public interface Scope {
/*
* @return defined scope local/instance/class variables and parameters, using reaching defs
*/
Collection<ScopeVariable> getDeclaredVariables(@NotNull PsiElement anchorElement);
/*
* @return defined scope local/instance/class variables and parameters, using reaching defs
*/
@Nullable
ScopeVariable getDeclaredVariable(@NotNull PsiElement anchorElement, @NotNull String name);
}
@@ -1,8 +1,8 @@
package com.jetbrains.python.codeInsight.dataflow;
package com.jetbrains.python.codeInsight.dataflow.scope;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyExceptPartNavigator;
import com.jetbrains.python.psi.impl.PyForStatementNavigator;
@@ -35,7 +35,7 @@ public class ScopeUtil {
return listCompExpression;
}
final ControlFlowOwner owner = PsiTreeUtil.getParentOfType(element, ControlFlowOwner.class, false);
final ScopeOwner owner = PsiTreeUtil.getParentOfType(element, ScopeOwner.class, false);
assert owner != null : "element should have not null controlflow owner";
return owner;
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.jetbrains.python.codeInsight.dataflow;
package com.jetbrains.python.codeInsight.dataflow.scope;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -0,0 +1,64 @@
package com.jetbrains.python.codeInsight.dataflow.scope.impl;
import com.intellij.codeInsight.controlflow.Instruction;
import com.intellij.codeInsight.dataflow.DFAEngine;
import com.intellij.codeInsight.dataflow.DFAMap;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.codeInsight.dataflow.PyReachingDefsDfaInstance;
import com.jetbrains.python.codeInsight.dataflow.PyReachingDefsSemilattice;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author oleg
*/
public class ScopeImpl implements Scope {
private final Instruction[] myFlow;
private List<DFAMap<ScopeVariable>> myCachedScopeVariables;
public ScopeImpl(final ScopeOwner flowOwner) {
myFlow = flowOwner.getControlFlow().getInstructions();
}
@NotNull
public Collection<ScopeVariable> getDeclaredVariables(@NotNull final PsiElement anchorElement) {
computeScopeVariables();
for (int i = 0; i < myFlow.length; i++) {
Instruction instruction = myFlow[i];
final PsiElement element = instruction.getElement();
if (element == anchorElement) {
return myCachedScopeVariables.get(i).values();
}
}
return Collections.emptyList();
}
public ScopeVariable getDeclaredVariable(@NotNull final PsiElement anchorElement,
@NotNull final String name) {
computeScopeVariables();
for (int i = 0; i < myFlow.length; i++) {
Instruction instruction = myFlow[i];
final PsiElement element = instruction.getElement();
if (element == anchorElement) {
return myCachedScopeVariables.get(i).get(name);
}
}
return null;
}
public List<DFAMap<ScopeVariable>> computeScopeVariables() {
if (myCachedScopeVariables == null) {
final PyReachingDefsDfaInstance dfaInstance = new PyReachingDefsDfaInstance();
final PyReachingDefsSemilattice semilattice = new PyReachingDefsSemilattice();
final DFAEngine<ScopeVariable> engine = new DFAEngine<ScopeVariable>(myFlow, dfaInstance, semilattice);
myCachedScopeVariables = engine.performDFA();
}
return myCachedScopeVariables;
}
}
@@ -1,7 +1,7 @@
package com.jetbrains.python.codeInsight.dataflow;
package com.jetbrains.python.codeInsight.dataflow.scope.impl;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeVariable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -3,7 +3,7 @@ package com.jetbrains.python.psi;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.StubBasedPsiElement;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.stubs.PyClassStub;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -12,8 +12,7 @@ import org.jetbrains.annotations.Nullable;
/**
* Represents a class declaration in source.
*/
public interface PyClass extends PsiNamedElement, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement<PyClassStub>,
ControlFlowOwner {
public interface PyClass extends PsiNamedElement, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement<PyClassStub>, ScopeOwner {
@NotNull
PyStatementList getStatementList();
@@ -6,13 +6,13 @@ package com.jetbrains.python.psi;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface PyFile extends PyElement, PsiFile, PyDocStringOwner, ControlFlowOwner {
public interface PyFile extends PyElement, PsiFile, PyDocStringOwner, ScopeOwner {
Key<Boolean> KEY_IS_DIRECTORY = Key.create("Dir impersonated by __init__.py");
Key<Boolean> KEY_EXCLUDE_BUILTINS = Key.create("Don't include builtins to processDeclaration results");
@@ -3,7 +3,7 @@ package com.jetbrains.python.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.StubBasedPsiElement;
import com.jetbrains.python.codeInsight.controlflow.ControlFlowOwner;
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
* @author yole
*/
public interface PyFunction extends PsiNamedElement, PyStatement, NameDefiner, PyDocStringOwner, StubBasedPsiElement<PyFunctionStub>,
ControlFlowOwner {
ScopeOwner {
PyFunction[] EMPTY_ARRAY = new PyFunction[0];
/**
@@ -13,6 +13,8 @@ import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.impl.ScopeImpl;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
@@ -355,6 +357,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
private SoftReference<ControlFlow> myControlFlowRef;
@NotNull
public ControlFlow getControlFlow() {
ControlFlow flow = getRefValue(myControlFlowRef);
@@ -365,6 +368,19 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
return flow;
}
private SoftReference<Scope> myScopeRef;
@NotNull
public Scope getScope() {
Scope scope = getRefValue(myScopeRef);
if (scope == null) {
scope = new ScopeImpl(this);
myScopeRef = new SoftReference<Scope>(scope);
}
return scope;
}
@Nullable
private static<T> T getRefValue(final SoftReference<T> reference){
return reference != null ? reference.get() : null;
@@ -17,6 +17,8 @@ import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.impl.ScopeImpl;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.resolve.PyResolveUtil;
@@ -270,6 +272,18 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression {
return flow;
}
private SoftReference<Scope> myScopeRef;
@NotNull
public Scope getScope() {
Scope scope = getRefValue(myScopeRef);
if (scope == null) {
scope = new ScopeImpl(this);
myScopeRef = new SoftReference<Scope>(scope);
}
return scope;
}
@Nullable
private static<T> T getRefValue(final SoftReference<T> reference){
return reference != null ? reference.get() : null;
@@ -28,6 +28,8 @@ import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonDosStringFinder;
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
import com.jetbrains.python.codeInsight.dataflow.scope.impl.ScopeImpl;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.codeInsight.controlflow.PyControlFlowBuilder;
import com.jetbrains.python.psi.stubs.PyClassStub;
@@ -195,6 +197,18 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
return flow;
}
private SoftReference<Scope> myScopeRef;
@NotNull
public Scope getScope() {
Scope scope = getRefValue(myScopeRef);
if (scope == null) {
scope = new ScopeImpl(this);
myScopeRef = new SoftReference<Scope>(scope);
}
return scope;
}
@Nullable
private static<T> T getRefValue(final SoftReference<T> reference){
return reference != null ? reference.get() : null;