Added names validator for Python Extract method refactoring

This commit is contained in:
Oleg Shpynov
2010-02-12 17:21:23 +03:00
parent c81053fc0b
commit 345be73093
3 changed files with 64 additions and 23 deletions
@@ -149,6 +149,7 @@ refactoring.extract.method.error.cannot.perform.refactoring.no.corresponding.loo
refactoring.extract.method.error.cannot.perform.refactoring.when.execution.flow.is.interrupted=Cannot perform refactoring when execution flow is interrupted
refactoring.extract.method.error.cannot.perform.refactoring.when.from.import.inside=Cannot perform refactoring with from import statement inside code block
refactoring.extract.method.error.cannot.perform.refactoring.using.selected.elements=Cannot perform extract method using selected element(s)
refactoring.extract.method.error.name.clash=Method name clashes with already existing method name
### Annotators ###
ANN.deleting.none=deleting None
@@ -20,10 +20,13 @@ import com.intellij.refactoring.extractMethod.AbstractVariableData;
import com.intellij.refactoring.extractMethod.ExtractMethodDecorator;
import com.intellij.refactoring.extractMethod.ExtractMethodValidator;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.hash.HashMap;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@@ -341,12 +344,16 @@ public class PyExtractMethodUtil {
private static Pair<String, AbstractVariableData[]> getNameAndVariableData(final Project project,
final CodeFragment fragment,
final PsiElement element) {
final ExtractMethodValidator validator = new PyExtractMethodValidator(element, project);
if (ApplicationManager.getApplication().isUnitTestMode()){
String name = System.getProperty(NAME);
if (name == null){
name = "foo";
}
final String result = validator.check(name);
if (result != null){
throw new CommonRefactoringUtil.RefactoringErrorHintException(result);
}
final List<AbstractVariableData> data = new ArrayList<AbstractVariableData>();
for (String in : fragment.getInputVariables()) {
final AbstractVariableData d = new AbstractVariableData();
@@ -358,16 +365,6 @@ public class PyExtractMethodUtil {
return Pair.create(name, data.toArray(new AbstractVariableData[data.size()]));
}
final ExtractMethodValidator validator = new ExtractMethodValidator() {
public String check(final String name) {
// TODO[oleg] implement context for name clashes
return null;
}
public boolean isValidName(final String name) {
return LanguageNamesValidation.INSTANCE.forLanguage(PythonLanguage.getInstance()).isIdentifier(name, project);
}
};
final boolean isMethod = PyPsiUtils.isMethodContext(element);
final ExtractMethodDecorator decorator = new ExtractMethodDecorator() {
public String createMethodPreview(final String methodName, final AbstractVariableData[] variableDatas) {
@@ -402,5 +399,49 @@ public class PyExtractMethodUtil {
return Pair.create(dialog.getMethodName(), dialog.getVariableData());
}
private static class PyExtractMethodValidator implements ExtractMethodValidator {
private final PsiElement myElement;
private final Project myProject;
private final Function<String, Boolean> myFunction;
public PyExtractMethodValidator(final PsiElement element, final Project project) {
myElement = element;
myProject = project;
final PsiNamedElement parent = PsiTreeUtil.getParentOfType(myElement, PyFile.class, PyClass.class);
if (parent instanceof PyFile){
final List<PyFunction> functions = ((PyFile)parent).getTopLevelFunctions();
myFunction = new Function<String, Boolean>() {
public Boolean fun(@NotNull final String s) {
for (PyFunction function : functions) {
if (s.equals(function.getName())){
return false;
}
}
return true;
}
};
} 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 {
myFunction = null;
}
}
public String check(final String name) {
if (myFunction != null && !myFunction.fun(name)){
return PyBundle.message("refactoring.extract.method.error.name.clash");
}
return null;
}
public boolean isValidName(final String name) {
return LanguageNamesValidation.INSTANCE.forLanguage(PythonLanguage.getInstance()).isIdentifier(name, myProject);
}
}
}
@@ -69,18 +69,17 @@ public class PyExtractMethodTest extends LightMarkedTestCase {
doTest("controlFlow/while_output.before.py", "bar", "controlFlow/while_output.after.py");
}
// TODO[oleg] implement me!!!
//public void testNameCollisionClass() throws Throwable {
// doTest("namesCollision/class.before.py", "hello", "Method name clashes with already existing method name");
//}
//
//public void testNameCollisionFile() throws Throwable {
// doTest("namesCollision/file.before.py", "hello", "Method name clashes with already existing method name");
//}
//
//public void testNameCollisionSuperClass() throws Throwable {
// doTest("namesCollision/superclass.before.py", "hello", "Method name clashes with already existing method name");
//}
public void testNameCollisionClass() throws Throwable {
doTest("namesCollision/class.before.py", "hello", "Method name clashes with already existing method name");
}
public void testNameCollisionFile() throws Throwable {
doTest("namesCollision/file.before.py", "hello", "Method name clashes with already existing method name");
}
public void testNameCollisionSuperClass() throws Throwable {
doTest("namesCollision/superclass.before.py", "hello", "Method name clashes with already existing method name");
}
public void testOutNotEmptyStatements() throws Throwable {
doTest("outNotEmpty/statements.before.py", "sum_squares", "outNotEmpty/statements.after.py");