PY-15653 Smart enter works better in case of function and class definitions without name element

This commit is contained in:
Mikhail Golubev
2015-04-21 15:14:25 +03:00
parent 6794f3299c
commit 3f519db066
7 changed files with 32 additions and 12 deletions
@@ -15,7 +15,6 @@
*/
package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
@@ -43,12 +42,21 @@ public class PyFunctionFixer extends PyFixer<PyFunction> {
final PsiElement colon = PyUtil.getFirstChildOfType(function, PyTokenTypes.COLON);
if (!isFakeFunction(function) && colon == null) {
final PyParameterList parameterList = function.getParameterList();
final Document document = editor.getDocument();
document.insertString(parameterList.getTextRange().getEndOffset(), ":");
if (function.getNameNode() == null) {
processor.registerUnresolvedError(parameterList.getTextOffset());
}
editor.getDocument().insertString(parameterList.getTextRange().getEndOffset(), ":");
}
}
private static boolean isFakeFunction(PyFunction function) {
/**
* Python parser can create empty function element without header and body solely to enclose {@link com.jetbrains.python.psi.PyDecoratorList}.
* Attempting to operate in the context of such "fake" function definition may lead to various kinds of malformed code and we want to
* avoid it.
*
* @return whether it's more the less proper function definition, i.e. it contains at least {@code def} keyword
*/
static boolean isFakeFunction(@NotNull PyFunction function) {
return function.getNode().findChildByType(PyTokenTypes.DEF_KEYWORD) == null;
}
}
@@ -40,22 +40,20 @@ public class PyParameterListFixer extends PyFixer<PyParameterList> {
}
@Override
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyParameterList psiElement) throws IncorrectOperationException {
public void doApply(@NotNull Editor editor, @NotNull PySmartEnterProcessor processor, @NotNull PyParameterList psiElement)
throws IncorrectOperationException {
final PsiElement lBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.OPEN_BRACES, 0);
final PsiElement rBrace = PyUtil.getChildByFilter(psiElement, PyTokenTypes.CLOSE_BRACES, 0);
if (!isFakeParameterList(psiElement) && (lBrace == null || rBrace == null)) {
final PyFunction pyFunction = as(psiElement.getParent(), PyFunction.class);
if (pyFunction != null && !PyFunctionFixer.isFakeFunction(pyFunction) && (lBrace == null || rBrace == null)) {
final Document document = editor.getDocument();
if (lBrace == null) {
document.insertString(psiElement.getTextRange().getStartOffset(), "(");
final String textToInsert = pyFunction.getNameNode() == null ? " (" : "(";
document.insertString(psiElement.getTextOffset(), textToInsert);
}
else {
document.insertString(psiElement.getTextRange().getEndOffset(), ")");
}
}
}
private static boolean isFakeParameterList(@NotNull PyParameterList parameterList) {
final PyFunction pyFunction = as(parameterList.getParent(), PyFunction.class);
return pyFunction != null && pyFunction.getNode().findChildByType(PyTokenTypes.DEF_KEYWORD) == null;
}
}
@@ -0,0 +1 @@
class<caret>
@@ -0,0 +1 @@
class <caret>:
@@ -0,0 +1 @@
def<caret>
@@ -0,0 +1 @@
def <caret>():
@@ -170,6 +170,16 @@ public class PySmartEnterTest extends PyTestCase {
}
}
// PY-15653
public void testClassKeywordOnly() {
doTest();
}
// PY-15653
public void testDefKeywordOnly() {
doTest();
}
// PY-12877
public void testWithTargetOmitted() {
doTest();