Merge branch 'master' of git.labs.intellij.net:idea/ultimate

This commit is contained in:
Dmitry Cheryasov
2010-05-14 04:07:13 +03:00
24 changed files with 176 additions and 36 deletions
@@ -41,7 +41,7 @@ public class PythonFoldingBuilder implements FoldingBuilder, DumbAware {
while (lastImport.getElementType() == TokenType.WHITE_SPACE) {
lastImport = lastImport.getTreePrev();
}
if (isImport(lastImport, false)) {
if (isImport(lastImport, false) && firstImport != lastImport) {
descriptors.add(new FoldingDescriptor(firstImport, new TextRange(firstImport.getStartOffset(),
lastImport.getTextRange().getEndOffset())));
}
@@ -15,10 +15,12 @@ import org.jetbrains.annotations.Nullable;
* User: dcheryasov
* Date: Apr 24, 2009 3:17:59 AM
*/
// intentional package level access
class AddImportHelper {
public class AddImportHelper {
private static final Logger LOG = Logger.getInstance("#" + AddImportHelper.class.getName());
private AddImportHelper() {
}
private static PsiElement getInsertPosition(final PsiFile file) {
PsiElement feeler = file.getFirstChild();
LOG.assertTrue(feeler != null);
@@ -0,0 +1,52 @@
package com.jetbrains.python.actions;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.template.TemplateBuilder;
import com.intellij.codeInsight.template.TemplateBuilderFactory;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyFile;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public class CreateClassQuickFix implements LocalQuickFix {
private final String myClassName;
private final PsiElement myAnchor;
public CreateClassQuickFix(String className, PsiElement anchor) {
myClassName = className;
myAnchor = anchor;
}
@NotNull
public String getName() {
return "Create class '" + myClassName + "'";
}
@NotNull
public String getFamilyName() {
return "Create Class";
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement anchor = myAnchor;
while(!(anchor.getParent() instanceof PyFile)) {
anchor = anchor.getParent();
}
PyClass pyClass = PyElementGenerator.getInstance(myAnchor.getProject()).createFromText(PyClass.class,
"class " + myClassName + "(object):\n pass");
pyClass = (PyClass) anchor.getParent().addBefore(pyClass, anchor);
pyClass = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(pyClass);
TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(pyClass);
builder.replaceElement(pyClass.getSuperClassExpressions() [0], "object");
builder.replaceElement(pyClass.getStatementList(), "pass");
builder.run();
}
}
@@ -199,13 +199,13 @@ public class PyBlock implements ASTBlock {
IElementType type2 = childNode2.getElementType();
if (type1 == PyElementTypes.CLASS_DECLARATION) {
int blankLines = mySettings.BLANK_LINES_AROUND_CLASS + 1;
return Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
return getBlankLinesForOption(mySettings.BLANK_LINES_AROUND_CLASS);
}
if (type1 == PyElementTypes.FUNCTION_DECLARATION || (type2 == PyElementTypes.FUNCTION_DECLARATION && type1 == PyElementTypes.CLASS_DECLARATION)) {
int blankLines = mySettings.BLANK_LINES_AROUND_METHOD + 1;
return Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
return getBlankLinesForOption(mySettings.BLANK_LINES_AROUND_METHOD);
}
if (isImportStatement(type1) && (isStatementOrDeclaration(type2) && !isImportStatement(type2))) {
return getBlankLinesForOption(mySettings.BLANK_LINES_AFTER_IMPORTS);
}
if (isStatementOrDeclaration(type1) && isStatementOrDeclaration(type2)) {
@@ -299,6 +299,10 @@ public class PyBlock implements ASTBlock {
return null;
}
private boolean isImportStatement(IElementType type1) {
return (type1 == PyElementTypes.IMPORT_STATEMENT || type1 == PyElementTypes.FROM_IMPORT_STATEMENT);
}
private static boolean isAround(IElementType type1, IElementType type2, final TokenSet tokenSet) {
return tokenSet.contains(type1) || tokenSet.contains(type2);
}
@@ -307,6 +311,11 @@ public class PyBlock implements ASTBlock {
return mySettings.getCustomSettings(PyCodeStyleSettings.class);
}
private Spacing getBlankLinesForOption(final int option) {
int blankLines = option + 1;
return Spacing.createSpacing(0, 0, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
}
private Spacing getSpacingForOption(boolean isOptionSet) {
int spaces = isOptionSet ? 1 : 0;
return Spacing.createSpacing(spaces, spaces, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
@@ -406,6 +406,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
if (ref_element != null && ref_is_importable && hint_action == null) {
actions.add(new AddImportAction(reference));
}
if (ref_text.length() > 2 && Character.isUpperCase(ref_text.charAt(0)) && !Character.isUpperCase(ref_text.charAt(1))) {
actions.add(new CreateClassQuickFix(ref_text, reference.getElement()));
}
}
}
String description = description_buf.toString();
@@ -1,5 +1,6 @@
package com.jetbrains.python.refactoring.introduce;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
@@ -39,7 +40,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
PyExpressionStatement statement = PsiTreeUtil.getParentOfType(expression, PyExpressionStatement.class);
if (statement != null) {
if (statement.getExpression() == expression) {
expression.delete();
statement.delete();
return;
}
}
@@ -85,7 +86,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
return ArrayUtil.toStringArray(res);
}
protected void performAction(@NotNull final Project project, Editor editor, PsiFile file, String name, boolean replaceAll, boolean hasConstructor) {
public void performAction(@NotNull final Project project, Editor editor, PsiFile file, String name, boolean replaceAll, boolean hasConstructor) {
if (!CommonRefactoringUtil.checkReadOnlyStatus(file)) {
return;
}
@@ -145,10 +146,13 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
initInConstructor = dialog.initInConstructor();
}
String assignmentText = name + " = " + expression.getText();
final PyAssignmentStatement declaration = createDeclaration(project, assignmentText);
PyAssignmentStatement declaration = createDeclaration(project, assignmentText);
assert name != null;
performReplace(project, declaration, expression, occurrences, name, replaceAll, initInConstructor);
declaration = performReplace(project, declaration, expression, occurrences, name, replaceAll, initInConstructor);
declaration = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(declaration);
editor.getCaretModel().moveToOffset(declaration.getTextRange().getEndOffset());
editor.getSelectionModel().removeSelection();
}
protected abstract String getHelpId();
@@ -172,24 +176,24 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
return PyRefactoringUtil.getOccurences(expression, context);
}
private void performReplace(@NotNull final Project project,
@NotNull final PyAssignmentStatement declaration,
@NotNull final PsiElement expression,
@NotNull final List<PsiElement> occurrences,
@NotNull final String name,
final boolean replaceAll,
final boolean initInConstructor) {
new WriteCommandAction(project, expression.getContainingFile()) {
protected void run(final Result result) throws Throwable {
private PyAssignmentStatement performReplace(@NotNull final Project project,
@NotNull final PyAssignmentStatement declaration,
@NotNull final PsiElement expression,
@NotNull final List<PsiElement> occurrences,
@NotNull final String name,
final boolean replaceAll,
final boolean initInConstructor) {
return new WriteCommandAction<PyAssignmentStatement>(project, expression.getContainingFile()) {
protected void run(final Result<PyAssignmentStatement> result) throws Throwable {
final Pair<PsiElement, TextRange> data = expression.getUserData(PyPsiUtils.SELECTION_BREAKS_AST_NODE);
if (data == null) {
addDeclaration(expression, declaration, occurrences, replaceAll, initInConstructor);
result.setResult((PyAssignmentStatement)addDeclaration(expression, declaration, occurrences, replaceAll, initInConstructor));
}
else {
addDeclaration(data.first, declaration, occurrences, replaceAll, initInConstructor);
result.setResult((PyAssignmentStatement)addDeclaration(data.first, declaration, occurrences, replaceAll, initInConstructor));
}
PyExpression newExpression = createExpression(project, name, declaration).getExpression();
PyExpression newExpression = createExpression(project, name, declaration);
if (replaceAll) {
for (PsiElement occurrence : occurrences) {
@@ -200,11 +204,11 @@ abstract public class IntroduceHandler implements RefactoringActionHandler {
replaceExpression(newExpression, project, expression);
}
}
}.execute();
}.execute().getResultObject();
}
protected PyExpressionStatement createExpression(Project project, String name, PyAssignmentStatement declaration) {
return PyElementGenerator.getInstance(project).createFromText(PyExpressionStatement.class, name);
protected PyExpression createExpression(Project project, String name, PyAssignmentStatement declaration) {
return PyElementGenerator.getInstance(project).createExpressionFromText(name);
}
@Nullable
@@ -60,10 +60,10 @@ public class FieldIntroduceHandler extends IntroduceHandler {
}
@Override
protected PyExpressionStatement createExpression(Project project, String name, PyAssignmentStatement declaration) {
protected PyExpression createExpression(Project project, String name, PyAssignmentStatement declaration) {
final String text = declaration.getText();
final String self_name = text.substring(0, text.indexOf('.'));
return PyElementGenerator.getInstance(project).createFromText(PyExpressionStatement.class, self_name + "." + name);
return PyElementGenerator.getInstance(project).createExpressionFromText(self_name + "." + name);
}
@Override
@@ -36,8 +36,7 @@ public class VariableIntroduceHandler extends IntroduceHandler {
PsiElement anchor = replaceAll ? findAnchor(occurrences) : PsiTreeUtil.getParentOfType(expression, PyStatement.class);
assert anchor != null;
final PsiElement parent = anchor.getParent();
parent.addBefore(declaration, anchor);
return parent.getParent();
return parent.addBefore(declaration, anchor);
}
private static PsiElement findAnchor(List<PsiElement> occurrences) {
@@ -0,0 +1 @@
this is commented
@@ -0,0 +1 @@
# this is commented
@@ -0,0 +1,3 @@
import sys
from os import *
def foo(): print sys.platform
@@ -0,0 +1,4 @@
import sys
from os import *
def foo(): print sys.platform
+3
View File
@@ -0,0 +1,3 @@
class XyzzyTest:
def testSimple(self):
c = <caret><warning descr="Unresolved reference 'Xyzzy'">Xyzzy</warning>()
@@ -0,0 +1,6 @@
class Xyzzy(object):
pass
class XyzzyTest:
def testSimple(self):
c = Xyzzy()
@@ -1,6 +1,7 @@
# Comments here
"Doc comment stays intact"
import ImportTarget
ImportTarget.foo
foo = 1
@@ -1,5 +1,6 @@
"Doc comment stays intact"
import ImportTarget
ImportTarget.foo
foo = 1
@@ -1,4 +1,5 @@
import ImportTarget
ImportTarget.foo
foo = 1
@@ -0,0 +1,3 @@
def foo():
a = 1<caret>
print "fooo"
@@ -0,0 +1,3 @@
def foo():
<selection>1</selection>
print "fooo"
@@ -1,5 +1,9 @@
package com.jetbrains.python;
import com.intellij.codeInsight.generation.actions.CommentByLineCommentAction;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
@@ -81,6 +85,19 @@ public class PyEditingTest extends PyLightFixtureTestCase {
myFixture.checkResultByFile("/editing/smartUnindent.after.py", true);
}
public void testUncommentWithSpace() throws Exception { // PY-980
myFixture.configureByFile("/editing/uncommentWithSpace.before.py");
myFixture.getEditor().getCaretModel().moveToLogicalPosition(new LogicalPosition(0, 1));
CommandProcessor.getInstance().executeCommand(myFixture.getProject(), new Runnable() {
public void run() {
CommentByLineCommentAction action = new CommentByLineCommentAction();
action.actionPerformed(new AnActionEvent(null, DataManager.getInstance().getDataContext(), "", action.getTemplatePresentation(),
ActionManager.getInstance(), 0));
}
}, "", null);
myFixture.checkResultByFile("/editing/uncommentWithSpace.after.py", true);
}
private String doTestTyping(final String text, final int offset, final char character) {
final PsiFile file = ApplicationManager.getApplication().runWriteAction(new Computable<PsiFile>() {
public PsiFile compute() {
@@ -36,6 +36,10 @@ public class PyFormatterTest extends PyLightFixtureTestCase {
doTest();
}
public void testBlankLineAfterImports() throws Exception {
doTest();
}
private void doTest() throws Exception {
myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -140,6 +140,10 @@ public class PyQuickFixTest extends PyLightFixtureTestCase {
PyBundle.message("QFIX.replace.equality"), true, true);
}
public void testAddClassFix() throws Exception {
doInspectionTest("AddClass.py", PyUnresolvedReferencesInspection.class, "Create class 'Xyzzy'", true, true);
}
@NonNls
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/inspections/";
@@ -1,9 +1,6 @@
package com.jetbrains.python;
import com.jetbrains.python.refactoring.PyCodeFragmentTest;
import com.jetbrains.python.refactoring.PyExtractMethodTest;
import com.jetbrains.python.refactoring.PyInlineLocalTest;
import com.jetbrains.python.refactoring.PyRenameTest;
import com.jetbrains.python.refactoring.*;
import com.jetbrains.python.refactoring.classes.PyExtractSuperclassTest;
import com.jetbrains.python.refactoring.classes.PyPullUpTest;
import com.jetbrains.python.refactoring.classes.PyPushDownTest;
@@ -56,7 +53,8 @@ public class PythonAllTestsSuite {
PyCodeFragmentTest.class,
PyOptimizeImportsTest.class,
PySmartEnterTest.class,
PyStatementMoverTest.class
PyStatementMoverTest.class,
PyIntroduceVariableTest.class
};
public static TestSuite suite() {
@@ -0,0 +1,21 @@
package com.jetbrains.python.refactoring;
import com.jetbrains.python.fixtures.PyLightFixtureTestCase;
import com.jetbrains.python.refactoring.introduce.variable.VariableIntroduceHandler;
/**
* @author yole
*/
public class PyIntroduceVariableTest extends PyLightFixtureTestCase {
@Override
protected String getTestDataPath() {
return super.getTestDataPath() + "/refactoring/introduceVariable";
}
public void testSimple() throws Exception {
myFixture.configureByFile("simple.py");
VariableIntroduceHandler handler = new VariableIntroduceHandler();
handler.performAction(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile(), "a", true, false);
myFixture.checkResultByFile("simple.after.py");
}
}