mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 21:01:48 +07:00
Merge branch 'python-fixes'
This commit is contained in:
@@ -8,14 +8,24 @@ import java.util.Set;
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyCodeFragment extends CodeFragment {
|
||||
private final Set<String> myGlobals;
|
||||
private final Set<String> myGlobalWrites;
|
||||
private final Set<String> myNonlocalWrites;
|
||||
|
||||
public PyCodeFragment(final Set<String> input, final Set<String> output, final Set<String> globals, final boolean returnInside) {
|
||||
public PyCodeFragment(final Set<String> input,
|
||||
final Set<String> output,
|
||||
final Set<String> globalWrites,
|
||||
final Set<String> nonlocalWrites,
|
||||
final boolean returnInside) {
|
||||
super(input, output, returnInside);
|
||||
myGlobals = globals;
|
||||
myGlobalWrites = globalWrites;
|
||||
myNonlocalWrites = nonlocalWrites;
|
||||
}
|
||||
|
||||
public Set<String> getGlobals() {
|
||||
return myGlobals;
|
||||
public Set<String> getGlobalWrites() {
|
||||
return myGlobalWrites;
|
||||
}
|
||||
|
||||
public Set<String> getNonlocalWrites() {
|
||||
return myNonlocalWrites;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +42,9 @@ public class PyCodeFragmentUtil {
|
||||
final List<Instruction> graph = Arrays.asList(flow.getInstructions());
|
||||
final List<Instruction> subGraph = getFragmentSubGraph(graph, start, end);
|
||||
final AnalysisResult subGraphAnalysis = analyseSubGraph(subGraph, start, end);
|
||||
if (subGraphAnalysis.regularExits > 0 && subGraphAnalysis.returns > 0) {
|
||||
throw new CannotCreateCodeFragmentException(
|
||||
PyBundle.message("refactoring.extract.method.error.cannot.perform.refactoring.when.execution.flow.is.interrupted"));
|
||||
}
|
||||
if (subGraphAnalysis.targetInstructions > 1) {
|
||||
if ((subGraphAnalysis.regularExits > 0 && subGraphAnalysis.returns > 0) ||
|
||||
subGraphAnalysis.targetInstructions > 1 ||
|
||||
subGraphAnalysis.outerLoopBreaks > 0) {
|
||||
throw new CannotCreateCodeFragmentException(
|
||||
PyBundle.message("refactoring.extract.method.error.cannot.perform.refactoring.when.execution.flow.is.interrupted"));
|
||||
}
|
||||
@@ -56,16 +54,17 @@ public class PyCodeFragmentUtil {
|
||||
}
|
||||
|
||||
final Set<String> globalWrites = getGlobalWrites(subGraph, owner);
|
||||
final Set<String> nonlocalWrites = getNonlocalWrites(subGraph, owner);
|
||||
|
||||
final Set<String> inputNames = new HashSet<String>();
|
||||
for (PsiElement element : filterElementsInScope(getInputElements(subGraph, graph), owner)) {
|
||||
final String name = getName(element);
|
||||
if (name != null) {
|
||||
// Ignore "self", it is generated automatically when extracting any method fragment
|
||||
if (PyPsiUtils.isMethodContext(element) && "self".equals(name)) {
|
||||
// Ignore "self" and "cls", they are generated automatically when extracting any method fragment
|
||||
if (resolvesToBoundMethodParameter(element)) {
|
||||
continue;
|
||||
}
|
||||
if (globalWrites.contains(name)) {
|
||||
if (globalWrites.contains(name) || nonlocalWrites.contains(name)) {
|
||||
continue;
|
||||
}
|
||||
inputNames.add(name);
|
||||
@@ -76,12 +75,41 @@ public class PyCodeFragmentUtil {
|
||||
for (PsiElement element : getOutputElements(subGraph, graph)) {
|
||||
final String name = getName(element);
|
||||
if (name != null) {
|
||||
if (globalWrites.contains(name) || nonlocalWrites.contains(name)) {
|
||||
continue;
|
||||
}
|
||||
outputNames.add(name);
|
||||
globalWrites.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
return new PyCodeFragment(inputNames, outputNames, globalWrites, subGraphAnalysis.returns > 0);
|
||||
return new PyCodeFragment(inputNames, outputNames, globalWrites, nonlocalWrites, subGraphAnalysis.returns > 0);
|
||||
}
|
||||
|
||||
private static boolean resolvesToBoundMethodParameter(@NotNull PsiElement element) {
|
||||
if (PyPsiUtils.isMethodContext(element)) {
|
||||
final PyFunction function = PsiTreeUtil.getParentOfType(element, PyFunction.class);
|
||||
if (function != null) {
|
||||
final PsiReference reference = element.getReference();
|
||||
if (reference != null) {
|
||||
final PsiElement resolved = reference.resolve();
|
||||
if (resolved instanceof PyParameter) {
|
||||
final PyParameterList parameterList = PsiTreeUtil.getParentOfType(resolved, PyParameterList.class);
|
||||
if (parameterList != null) {
|
||||
final PyParameter[] parameters = parameterList.getParameters();
|
||||
if (parameters.length > 0) {
|
||||
if (resolved == parameters[0]) {
|
||||
final PyFunction.Modifier modifier = function.getModifier();
|
||||
if (modifier == null || modifier == PyFunction.Modifier.CLASSMETHOD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -135,12 +163,14 @@ public class PyCodeFragmentUtil {
|
||||
private final int targetInstructions;
|
||||
private final int regularExits;
|
||||
private final int returns;
|
||||
private final int outerLoopBreaks;
|
||||
|
||||
public AnalysisResult(int starImports, int targetInstructions, int returns, int regularExits) {
|
||||
public AnalysisResult(int starImports, int targetInstructions, int returns, int regularExits, int outerLoopBreaks) {
|
||||
this.starImports = starImports;
|
||||
this.targetInstructions = targetInstructions;
|
||||
this.regularExits = regularExits;
|
||||
this.returns = returns;
|
||||
this.outerLoopBreaks = outerLoopBreaks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +180,7 @@ public class PyCodeFragmentUtil {
|
||||
int regularSources = 0;
|
||||
final Set<Instruction> targetInstructions = new HashSet<Instruction>();
|
||||
int starImports = 0;
|
||||
int outerLoopBreaks = 0;
|
||||
|
||||
for (Pair<Instruction, Instruction> edge : getOutgoingEdges(subGraph)) {
|
||||
final Instruction sourceInstruction = edge.getFirst();
|
||||
@@ -173,17 +204,23 @@ public class PyCodeFragmentUtil {
|
||||
}
|
||||
}
|
||||
|
||||
for (Instruction instruction : subGraph) {
|
||||
final PsiElement element = instruction.getElement();
|
||||
final Set<PsiElement> subGraphElements = getSubGraphElements(subGraph);
|
||||
for (PsiElement element : subGraphElements) {
|
||||
if (element instanceof PyFromImportStatement) {
|
||||
final PyFromImportStatement fromImportStatement = (PyFromImportStatement)element;
|
||||
if (fromImportStatement.getStarImportElement() != null) {
|
||||
starImports++;
|
||||
}
|
||||
}
|
||||
if (element instanceof PyContinueStatement || element instanceof PyBreakStatement) {
|
||||
final PyLoopStatement loopStatement = PsiTreeUtil.getParentOfType(element, PyLoopStatement.class);
|
||||
if (loopStatement != null && !subGraphElements.contains(loopStatement)) {
|
||||
outerLoopBreaks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AnalysisResult(starImports, targetInstructions.size(), returnSources, regularSources);
|
||||
return new AnalysisResult(starImports, targetInstructions.size(), returnSources, regularSources, outerLoopBreaks);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -299,6 +336,21 @@ public class PyCodeFragmentUtil {
|
||||
return globalWrites;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getNonlocalWrites(@NotNull List<Instruction> instructions, @NotNull ScopeOwner owner) {
|
||||
final Scope scope = ControlFlowCache.getScope(owner);
|
||||
final Set<String> nonlocalWrites = new LinkedHashSet<String>();
|
||||
for (Instruction instruction : getWriteInstructions(instructions)) {
|
||||
if (instruction instanceof ReadWriteInstruction) {
|
||||
final String name = ((ReadWriteInstruction)instruction).getName();
|
||||
if (scope.isNonlocal(name)) {
|
||||
nonlocalWrites.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nonlocalWrites;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiElement> multiResolve(@NotNull PsiReference reference) {
|
||||
if (reference instanceof PsiPolyVariantReference) {
|
||||
@@ -310,6 +362,11 @@ public class PyCodeFragmentUtil {
|
||||
resolved.add(element);
|
||||
}
|
||||
}
|
||||
for (PsiElement element : resolved) {
|
||||
if (element instanceof PyClass) {
|
||||
return Collections.singletonList(element);
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
final PsiElement element = reference.resolve();
|
||||
|
||||
+59
-13
@@ -34,16 +34,17 @@ import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.codeInsight.codeFragment.PyCodeFragment;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.Scope;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyFunctionBuilder;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
@@ -101,8 +102,8 @@ public class PyExtractMethodUtil {
|
||||
final PsiElement firstElement = elementsRange.get(0);
|
||||
final boolean isMethod = PyPsiUtils.isMethodContext(firstElement);
|
||||
processParameters(project, generatedMethod, variableData, isMethod, isClassMethod, isStaticMethod);
|
||||
|
||||
processGlobalWrites(generatedMethod, fragment);
|
||||
processNonlocalWrites(generatedMethod, fragment);
|
||||
|
||||
// Generating call element
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
@@ -152,8 +153,8 @@ public class PyExtractMethodUtil {
|
||||
// Process parameters
|
||||
final boolean isMethod = PyPsiUtils.isMethodContext(elementsRange.get(0));
|
||||
processParameters(project, generatedMethod, variableData, isMethod, isClassMethod, isStaticMethod);
|
||||
|
||||
processGlobalWrites(generatedMethod, fragment);
|
||||
processNonlocalWrites(generatedMethod, fragment);
|
||||
|
||||
// Generate call element
|
||||
builder.append(" = ");
|
||||
@@ -177,12 +178,19 @@ public class PyExtractMethodUtil {
|
||||
}
|
||||
|
||||
private static void processGlobalWrites(@NotNull PyFunction function, @NotNull PyCodeFragment fragment) {
|
||||
final Set<String> globals = fragment.getGlobals();
|
||||
if (!globals.isEmpty()) {
|
||||
final Set<String> globalWrites = fragment.getGlobalWrites();
|
||||
final Set<String> newGlobalNames = new LinkedHashSet<String>();
|
||||
final Scope scope = ControlFlowCache.getScope(function);
|
||||
for (String name : globalWrites) {
|
||||
if (!scope.isGlobal(name)) {
|
||||
newGlobalNames.add(name);
|
||||
}
|
||||
}
|
||||
if (!newGlobalNames.isEmpty()) {
|
||||
final PyElementGenerator generator = PyElementGenerator.getInstance(function.getProject());
|
||||
final PyGlobalStatement globalStatement = generator.createFromText(LanguageLevel.forElement(function),
|
||||
PyGlobalStatement.class,
|
||||
"global " + StringUtil.join(globals, ", "));
|
||||
"global " + StringUtil.join(newGlobalNames, ", "));
|
||||
final PyStatementList statementList = function.getStatementList();
|
||||
if (statementList != null) {
|
||||
statementList.addBefore(globalStatement, statementList.getFirstChild());
|
||||
@@ -190,6 +198,28 @@ public class PyExtractMethodUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void processNonlocalWrites(@NotNull PyFunction function, @NotNull PyCodeFragment fragment) {
|
||||
final Set<String> nonlocalWrites = fragment.getNonlocalWrites();
|
||||
final Set<String> newNonlocalNames = new LinkedHashSet<String>();
|
||||
final Scope scope = ControlFlowCache.getScope(function);
|
||||
for (String name : nonlocalWrites) {
|
||||
if (!scope.isNonlocal(name)) {
|
||||
newNonlocalNames.add(name);
|
||||
}
|
||||
}
|
||||
if (!newNonlocalNames.isEmpty()) {
|
||||
final PyElementGenerator generator = PyElementGenerator.getInstance(function.getProject());
|
||||
final PyNonlocalStatement nonlocalStatement = generator.createFromText(LanguageLevel.forElement(function),
|
||||
PyNonlocalStatement.class,
|
||||
"nonlocal " + StringUtil.join(newNonlocalNames, ", "));
|
||||
final PyStatementList statementList = function.getStatementList();
|
||||
if (statementList != null) {
|
||||
statementList.addBefore(nonlocalStatement, statementList.getFirstChild());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void appendSelf(PsiElement firstElement, StringBuilder builder, boolean staticMethod) {
|
||||
if (staticMethod) {
|
||||
final PyClass containingClass = PsiTreeUtil.getParentOfType(firstElement, PyClass.class);
|
||||
@@ -523,7 +553,13 @@ public class PyExtractMethodUtil {
|
||||
public PyExtractMethodValidator(final PsiElement element, final Project project) {
|
||||
myElement = element;
|
||||
myProject = project;
|
||||
final PsiNamedElement parent = PsiTreeUtil.getParentOfType(myElement, PyFile.class, PyClass.class);
|
||||
|
||||
ScopeOwner owner = ScopeUtil.getScopeOwner(myElement);
|
||||
if (owner instanceof PyFunction) {
|
||||
owner = ScopeUtil.getScopeOwner(owner);
|
||||
}
|
||||
final ScopeOwner parent = owner;
|
||||
|
||||
if (parent instanceof PyFile){
|
||||
final List<PyFunction> functions = ((PyFile)parent).getTopLevelFunctions();
|
||||
myFunction = new Function<String, Boolean>() {
|
||||
@@ -536,14 +572,24 @@ public class PyExtractMethodUtil {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} else
|
||||
if (parent instanceof PyClass){
|
||||
}
|
||||
else if (parent instanceof PyClass){
|
||||
myFunction = new Function<String, Boolean>() {
|
||||
public Boolean fun(@NotNull final String s) {
|
||||
return ((PyClass) parent).findMethodByName(s, true) == null;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
}
|
||||
else if (parent instanceof PyFunction) {
|
||||
final Scope scope = ControlFlowCache.getScope(parent);
|
||||
myFunction = new Function<String, Boolean>() {
|
||||
@Override
|
||||
public Boolean fun(String s) {
|
||||
return !scope.containsDeclaration(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
myFunction = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
__author__ = 'user'
|
||||
@@ -1,8 +1,9 @@
|
||||
print("start")
|
||||
<begin>
|
||||
import foo
|
||||
<end>
|
||||
foo.bar
|
||||
def foo():
|
||||
print("start")
|
||||
<begin>
|
||||
import foo
|
||||
<end>
|
||||
foo.bar
|
||||
<result>
|
||||
In:
|
||||
Out:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
print("start")
|
||||
<begin>
|
||||
aaa = 123
|
||||
<end>
|
||||
print(aaa)
|
||||
def foo():
|
||||
print("start")
|
||||
<begin>
|
||||
aaa = 123
|
||||
<end>
|
||||
print(aaa)
|
||||
<result>
|
||||
In:
|
||||
Out:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
def foo():
|
||||
return bbb
|
||||
|
||||
aaa = foo() && ccc
|
||||
@@ -0,0 +1 @@
|
||||
aaa = <selection>bbb</selection> && ccc
|
||||
@@ -0,0 +1,6 @@
|
||||
def bar(r_new):
|
||||
return PI * r_new ** 2
|
||||
|
||||
|
||||
def cylinder_volume(r, h):
|
||||
h * bar(r)
|
||||
@@ -0,0 +1,2 @@
|
||||
def cylinder_volume(r, h):
|
||||
h * <selection>PI * r ** 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class PyCharm:
|
||||
def bar():
|
||||
print("Hello Pycharm!")
|
||||
|
||||
bar()
|
||||
@@ -0,0 +1,2 @@
|
||||
class PyCharm:
|
||||
<selection>print("Hello Pycharm!")</selection>
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
class C:
|
||||
@classmethod
|
||||
def baz(cls):
|
||||
print "hello world"
|
||||
print('foo', cls)
|
||||
|
||||
@classmethod
|
||||
def foo(cls):
|
||||
cls.baz()
|
||||
cls.baz()
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
@classmethod
|
||||
def foo(cls):
|
||||
<selection>print('foo', cls)</selection>
|
||||
@@ -0,0 +1,11 @@
|
||||
def bar():
|
||||
class C(object):
|
||||
pass
|
||||
|
||||
c = C()
|
||||
return c
|
||||
|
||||
|
||||
def foo():
|
||||
c = bar()
|
||||
return c
|
||||
@@ -0,0 +1,5 @@
|
||||
def foo():
|
||||
<selection>class C(object):
|
||||
pass
|
||||
c = C()</selection>
|
||||
return c
|
||||
@@ -0,0 +1,8 @@
|
||||
def plus(a_new, b_new):
|
||||
return a_new + b_new * 123
|
||||
|
||||
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
c = plus(a, b)
|
||||
@@ -0,0 +1,4 @@
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
c = <selection>a + b * 123</selection>
|
||||
@@ -0,0 +1,4 @@
|
||||
def foo(xs):
|
||||
for x in xs:
|
||||
<selection>if not x:
|
||||
continue</selection>
|
||||
@@ -1,10 +1,10 @@
|
||||
a = 2
|
||||
b = 3
|
||||
|
||||
def bar():
|
||||
global a
|
||||
a = a + 1
|
||||
global a, c
|
||||
a = a + b
|
||||
c = a * 2
|
||||
return c
|
||||
|
||||
c = bar()
|
||||
bar()
|
||||
print(c)
|
||||
@@ -1,4 +1,5 @@
|
||||
a = 2
|
||||
<selection>a = a + 1
|
||||
b = 3
|
||||
<selection>a = a + b
|
||||
c = a * 2</selection>
|
||||
print(c)
|
||||
@@ -0,0 +1,7 @@
|
||||
class C:
|
||||
def bar(self):
|
||||
for x in [1, 2]:
|
||||
print x
|
||||
|
||||
def foo(self):
|
||||
self.bar()
|
||||
@@ -0,0 +1,4 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>for x in [1, 2]:
|
||||
print x</selection>
|
||||
@@ -0,0 +1,8 @@
|
||||
class Foo(X, Y, Z):
|
||||
def bar(self, base_new):
|
||||
try: base_new.__init__(self)
|
||||
except AttributeError: pass
|
||||
|
||||
def __init__(self):
|
||||
for base in self__class__.__bases__:
|
||||
self.bar(base)
|
||||
@@ -0,0 +1,5 @@
|
||||
class Foo(X, Y, Z):
|
||||
def __init__(self):
|
||||
for base in self__class__.__bases__:
|
||||
<selection>try: base.__init__(self)
|
||||
except AttributeError: pass</selection>
|
||||
@@ -0,0 +1,9 @@
|
||||
class C:
|
||||
def bar(self):
|
||||
if (self.cond):
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
|
||||
def foo(self):
|
||||
return self.bar()
|
||||
@@ -0,0 +1,6 @@
|
||||
class C:
|
||||
def foo(self):
|
||||
<selection>if (self.cond):
|
||||
return 1
|
||||
else:
|
||||
return 2</selection>
|
||||
@@ -0,0 +1,5 @@
|
||||
class A:
|
||||
def hello():
|
||||
pass
|
||||
|
||||
<selection>print("Hello")</selection>
|
||||
@@ -0,0 +1,4 @@
|
||||
def hello():
|
||||
pass
|
||||
|
||||
<selection>print("Hello")</selection>
|
||||
@@ -0,0 +1,7 @@
|
||||
class A:
|
||||
def hello(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
def foo(self):
|
||||
<selection>print("Hello")</selection>
|
||||
@@ -0,0 +1,13 @@
|
||||
def foo():
|
||||
x = 1
|
||||
|
||||
def baz():
|
||||
nonlocal x
|
||||
x = 2
|
||||
|
||||
def bar():
|
||||
nonlocal x
|
||||
baz()
|
||||
print(x)
|
||||
bar()
|
||||
foo()
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo():
|
||||
x = 1
|
||||
def bar():
|
||||
nonlocal x
|
||||
<selection>x = 2</selection>
|
||||
print(x)
|
||||
bar()
|
||||
foo()
|
||||
@@ -0,0 +1,12 @@
|
||||
def sum_squares(a_new, result_new):
|
||||
while a_new < 10:
|
||||
result_new += a_new * a_new
|
||||
a_new += 1
|
||||
return result_new
|
||||
|
||||
|
||||
def f():
|
||||
a = 10
|
||||
result = 0
|
||||
result = sum_squares(a, result)
|
||||
print("Sum of squares: " + result)
|
||||
@@ -0,0 +1,7 @@
|
||||
def f():
|
||||
a = 10
|
||||
result = 0
|
||||
<selection>while a < 10:
|
||||
result += a * a
|
||||
a += 1</selection>
|
||||
print("Sum of squares: " + result)
|
||||
@@ -0,0 +1,12 @@
|
||||
def sum_squares(a_new):
|
||||
result = 0
|
||||
while a_new < 10:
|
||||
result += a_new * a_new
|
||||
a_new += 1
|
||||
return a_new, result
|
||||
|
||||
|
||||
def f():
|
||||
a = 1
|
||||
a, result = sum_squares(a)
|
||||
print("Sum of squares: " + a + " = " + result)
|
||||
@@ -0,0 +1,7 @@
|
||||
def f():
|
||||
a = 1
|
||||
<selection>result = 0
|
||||
while a < 10:
|
||||
result += a * a
|
||||
a += 1</selection>
|
||||
print("Sum of squares: " + a + " = " + result)
|
||||
@@ -0,0 +1,6 @@
|
||||
def bar(a_new):
|
||||
print(a_new)
|
||||
|
||||
|
||||
def foo(a):
|
||||
bar(a)
|
||||
@@ -0,0 +1,2 @@
|
||||
def foo(a):
|
||||
<selection>print(a)</selection>
|
||||
@@ -0,0 +1,25 @@
|
||||
class Foo:
|
||||
def __init__(self):
|
||||
self.tmp = False
|
||||
|
||||
def bar(self, condition3_new, condition4_new):
|
||||
self.tmp2 = True
|
||||
if condition3_new:
|
||||
print(condition3_new)
|
||||
if condition4_new:
|
||||
print(condition4_new)
|
||||
print("misterious extract method test")
|
||||
|
||||
def extract_method(self, condition1, condition2, condition3, condition4):
|
||||
list = (1, 2, 3)
|
||||
a = 6
|
||||
b = False
|
||||
if a in list or self.tmp:
|
||||
if condition1:
|
||||
print(condition1)
|
||||
if b is not condition2:
|
||||
print(b)
|
||||
else:
|
||||
self.bar(condition3, condition4)
|
||||
f = Foo()
|
||||
f.extract_method(True, True, True, True)
|
||||
@@ -0,0 +1,22 @@
|
||||
class Foo:
|
||||
def __init__(self):
|
||||
self.tmp = False
|
||||
|
||||
def extract_method(self, condition1, condition2, condition3, condition4):
|
||||
list = (1, 2, 3)
|
||||
a = 6
|
||||
b = False
|
||||
if a in list or self.tmp:
|
||||
if condition1:
|
||||
print(condition1)
|
||||
if b is not condition2:
|
||||
print(b)
|
||||
else:
|
||||
<selection>self.tmp2 = True
|
||||
if condition3:
|
||||
print(condition3)
|
||||
if condition4:
|
||||
print(condition4)
|
||||
print("misterious extract method test")</selection>
|
||||
f = Foo()
|
||||
f.extract_method(True, True, True, True)
|
||||
@@ -0,0 +1,8 @@
|
||||
def foo(a_new, b_new):
|
||||
print(a_new + b_new * 123)
|
||||
|
||||
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
foo(a, b)
|
||||
@@ -0,0 +1,4 @@
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
<selection>print(a + b * 123)</selection>
|
||||
@@ -0,0 +1,10 @@
|
||||
def foo():
|
||||
if foo():
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
return foo()
|
||||
|
||||
|
||||
bar
|
||||
@@ -0,0 +1,8 @@
|
||||
<selection>
|
||||
if foo():
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
</selection>
|
||||
|
||||
bar
|
||||
@@ -0,0 +1,10 @@
|
||||
def foo(a_new, b_new):
|
||||
puts(a_new + b_new * 123)
|
||||
print("Hello from extract method")
|
||||
|
||||
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
foo(a, b)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
def f():
|
||||
a = 1
|
||||
b = 1
|
||||
<selection>puts(a + b * 123)
|
||||
print("Hello from extract method")</selection>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
def bar(a_new):
|
||||
do_smth
|
||||
a_new += 1
|
||||
return a_new
|
||||
|
||||
|
||||
def f():
|
||||
a = 1
|
||||
while a < 10:
|
||||
a = bar(a)
|
||||
print(a)
|
||||
@@ -0,0 +1,6 @@
|
||||
def f():
|
||||
a = 1
|
||||
while a < 10:
|
||||
<selection>do_smth
|
||||
a+=1</selection>
|
||||
print(a)
|
||||
@@ -0,0 +1 @@
|
||||
<selection>from mymodule import *</selection>
|
||||
@@ -0,0 +1,13 @@
|
||||
class Settings(patterns.Observer, UnicodeAwareConfigParser):
|
||||
def __init__(self):
|
||||
pass
|
||||
def set(self, section, option, value, new=False):
|
||||
<selection>if new:
|
||||
currentValue = 'a new option, so use something as current value'\
|
||||
' that is unlikely to be equal to the new value'</selection>
|
||||
else:
|
||||
currentValue = self.get(section, option)
|
||||
if value != currentValue:
|
||||
patterns.Event('before.%s.%s'%(section, option), self, value).send()
|
||||
super(Settings, self).set(section, option, value)
|
||||
patterns.Event('%s.%s'%(section, option), self, value).send()
|
||||
@@ -1,4 +0,0 @@
|
||||
class C:
|
||||
@classmethod
|
||||
def foo(cls):
|
||||
<selection>print "hello world"</selection>
|
||||
@@ -1,162 +1,179 @@
|
||||
package com.jetbrains.python.refactoring;
|
||||
|
||||
import com.intellij.lang.LanguageRefactoringSupport;
|
||||
import com.intellij.lang.refactoring.RefactoringSupportProvider;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.fixtures.LightMarkedTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.refactoring.extractmethod.PyExtractMethodUtil;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
*/
|
||||
public class PyExtractMethodTest extends LightMarkedTestCase {
|
||||
private void doTest(final String testPath,
|
||||
final String name,
|
||||
final String result) {
|
||||
|
||||
myFixture.configureByFile("/refactoring/extractmethod/" + testPath);
|
||||
final RefactoringActionHandler handler = LanguageRefactoringSupport.INSTANCE.forLanguage(PythonLanguage.getInstance()).getExtractMethodHandler();
|
||||
private void doTest(String newName, LanguageLevel level) {
|
||||
setLanguageLevel(level);
|
||||
try {
|
||||
System.setProperty(PyExtractMethodUtil.NAME, name);
|
||||
try {
|
||||
handler.invoke(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), ((EditorEx) myFixture.getEditor()).getDataContext());
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (result.endsWith(".py")) { // expected output file, not an exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals(result, e.getMessage());
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
System.clearProperty(PyExtractMethodUtil.NAME);
|
||||
doTest(newName);
|
||||
}
|
||||
finally {
|
||||
setLanguageLevel(null);
|
||||
}
|
||||
myFixture.checkResultByFile("/refactoring/extractmethod/" + result);
|
||||
}
|
||||
|
||||
private void doTest(String newName) {
|
||||
final String testName = getTestName(false);
|
||||
doTest(testName + ".before.py", newName, testName + ".after.py");
|
||||
final String beforeName = testName + ".before.py";
|
||||
final String afterName = testName + ".after.py";
|
||||
final String dir = "refactoring/extractmethod/";
|
||||
|
||||
myFixture.configureByFile(dir + beforeName);
|
||||
final RefactoringSupportProvider provider = LanguageRefactoringSupport.INSTANCE.forLanguage(PythonLanguage.getInstance());
|
||||
assertNotNull(provider);
|
||||
final RefactoringActionHandler handler = provider.getExtractMethodHandler();
|
||||
assertNotNull(handler);
|
||||
final Editor editor = myFixture.getEditor();
|
||||
assertInstanceOf(editor, EditorEx.class);
|
||||
System.setProperty(PyExtractMethodUtil.NAME, newName);
|
||||
try {
|
||||
handler.invoke(myFixture.getProject(), editor, myFixture.getFile(), ((EditorEx)editor).getDataContext());
|
||||
}
|
||||
finally {
|
||||
System.clearProperty(PyExtractMethodUtil.NAME);
|
||||
}
|
||||
myFixture.checkResultByFile(dir + afterName);
|
||||
}
|
||||
|
||||
private void doFail(String newName, String message) {
|
||||
try {
|
||||
doTest(newName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertEquals(message, e.getMessage());
|
||||
return;
|
||||
}
|
||||
fail("No exception was thrown");
|
||||
}
|
||||
|
||||
public void testParameter() {
|
||||
doTest("outEmpty/parameter.before.py", "bar", "outEmpty/parameter.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testBreakAst() {
|
||||
doTest("outEmpty/break_ast.before.py", "bar", "outEmpty/break_ast.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testExpression() {
|
||||
doTest("outEmpty/expression.before.py", "plus", "outEmpty/expression.after.py");
|
||||
doTest("plus");
|
||||
}
|
||||
|
||||
public void testStatement() {
|
||||
doTest("outEmpty/statement.before.py", "foo", "outEmpty/statement.after.py");
|
||||
doTest("foo");
|
||||
}
|
||||
|
||||
public void testStatements() {
|
||||
doTest("outEmpty/statements.before.py", "foo", "outEmpty/statements.after.py");
|
||||
doTest("foo");
|
||||
}
|
||||
|
||||
public void testStatementReturn() {
|
||||
doTest("outEmpty/statement_return.before.py", "foo", "outEmpty/statement_return.after.py");
|
||||
doTest("foo");
|
||||
}
|
||||
|
||||
public void testBinaryExpression() {
|
||||
doTest("controlFlow/binary_expr.before.py", "foo", "controlFlow/binary_expr.after.py");
|
||||
doTest("foo");
|
||||
}
|
||||
|
||||
public void testWhileOutput() {
|
||||
doTest("controlFlow/while_output.before.py", "bar", "controlFlow/while_output.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testNameCollisionClass() {
|
||||
doTest("namesCollision/class.before.py", "hello", "Method name clashes with already existing method name");
|
||||
doFail("hello", "Method name clashes with already existing method name");
|
||||
}
|
||||
|
||||
public void testNameCollisionFile() {
|
||||
doTest("namesCollision/file.before.py", "hello", "Method name clashes with already existing method name");
|
||||
doFail("hello", "Method name clashes with already existing method name");
|
||||
}
|
||||
|
||||
public void testNameCollisionSuperClass() {
|
||||
doTest("namesCollision/superclass.before.py", "hello", "Method name clashes with already existing method name");
|
||||
doFail("hello", "Method name clashes with already existing method name");
|
||||
}
|
||||
|
||||
public void testOutNotEmptyStatements() {
|
||||
doTest("outNotEmpty/statements.before.py", "sum_squares", "outNotEmpty/statements.after.py");
|
||||
doTest("sum_squares");
|
||||
}
|
||||
|
||||
public void testOutNotEmptyStatements2() {
|
||||
doTest("outNotEmpty/statements2.before.py", "sum_squares", "outNotEmpty/statements2.after.py");
|
||||
doTest("sum_squares");
|
||||
}
|
||||
|
||||
// PY-2903
|
||||
public void _testComment() {
|
||||
doTest("comment.before.py", "bar", "comment.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testFile() {
|
||||
doTest("file.before.py", "bar", "file.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
|
||||
public void testMethod() {
|
||||
doTest("context/method.before.py", "bar", "context/method.after.py");
|
||||
public void testMethodContext() {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testMethodIndent() {
|
||||
doTest("context/methodindent.before.py", "bar", "context/methodindent.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testMethodReturn() {
|
||||
doTest("context/methodreturn.before.py", "bar", "context/methodreturn.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testWrongSelectionIfPart() {
|
||||
doTest("wrongSelection/ifpart.before.py", "bar", "Cannot perform extract method using selected element(s)");
|
||||
doFail("bar", "Cannot perform extract method using selected element(s)");
|
||||
}
|
||||
|
||||
public void testFromImportStatement() {
|
||||
doTest("wrongSelection/fromimport.before.py", "bar", "Cannot perform refactoring with from import statement inside code block");
|
||||
public void testWrongSelectionFromImportStar() {
|
||||
doFail("bar", "Cannot perform refactoring with from import statement inside code block");
|
||||
}
|
||||
|
||||
public void testPy479() {
|
||||
doTest("outEmpty/py479.before.py", "bar", "outEmpty/py479.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testClass() {
|
||||
doTest("context/class.before.py", "bar", "context/class.after.py");
|
||||
public void testClassContext() {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testConditionalReturn() {
|
||||
doTest("conditionalreturn.before.py", "bar", "Cannot perform refactoring when execution flow is interrupted");
|
||||
doFail("bar", "Cannot perform refactoring when execution flow is interrupted");
|
||||
}
|
||||
|
||||
public void testReturnTuple() {
|
||||
doTest("return_tuple.before.py", "bar", "return_tuple.after.py");
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
public void testComment2() {
|
||||
doTest("comment2.before.py", "baz", "comment2.after.py");
|
||||
doTest("baz");
|
||||
}
|
||||
|
||||
public void testElseBody() {
|
||||
doTest("elsebody.before.py", "baz", "elsebody.after.py");
|
||||
doTest("baz");
|
||||
}
|
||||
|
||||
public void testClassMethod() {
|
||||
doTest("classmethod.before.py", "baz", "classmethod.after.py");
|
||||
doTest("baz");
|
||||
}
|
||||
|
||||
public void testStaticMethod() {
|
||||
doTest("staticmethod.before.py", "baz", "staticmethod.after.py");
|
||||
doTest("baz");
|
||||
}
|
||||
|
||||
// PY-5123
|
||||
public void testMethodInIf() {
|
||||
doTest("methodInIf.before.py", "baz", "methodInIf.after.py");
|
||||
doTest("baz");
|
||||
}
|
||||
|
||||
// PY-6081
|
||||
@@ -203,4 +220,19 @@ public class PyExtractMethodTest extends LightMarkedTestCase {
|
||||
public void testGlobalToplevelAssignment() {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
// PY-6623
|
||||
public void testForLoopContinue() {
|
||||
doFail("bar", "Cannot perform refactoring when execution flow is interrupted");
|
||||
}
|
||||
|
||||
// PY-6622
|
||||
public void testClassWithoutInit() {
|
||||
doTest("bar");
|
||||
}
|
||||
|
||||
// PY-6625
|
||||
public void testNonlocal() {
|
||||
doTest("baz", LanguageLevel.PYTHON30);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user