From 98c20d6159d9e40076532c89a168be4849035e10 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 16 Dec 2010 14:08:03 +0300 Subject: [PATCH 01/10] 'ignore unresolved identifier' is a low-priority action --- .../com/jetbrains/python/actions/AddIgnoredIdentifierFix.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/actions/AddIgnoredIdentifierFix.java b/python/src/com/jetbrains/python/actions/AddIgnoredIdentifierFix.java index 1eb3b7bfb2bb..53cec5ae626e 100644 --- a/python/src/com/jetbrains/python/actions/AddIgnoredIdentifierFix.java +++ b/python/src/com/jetbrains/python/actions/AddIgnoredIdentifierFix.java @@ -1,5 +1,6 @@ package com.jetbrains.python.actions; +import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.codeInspection.InspectionProfile; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; @@ -12,7 +13,7 @@ import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class AddIgnoredIdentifierFix implements LocalQuickFix { +public class AddIgnoredIdentifierFix implements LocalQuickFix, LowPriorityAction { private final String myIdentifier; public AddIgnoredIdentifierFix(String identifier) { From 7a7d9e72e15598ae3b45e3176f134d1f659a8c13 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 15:34:09 +0300 Subject: [PATCH 02/10] fixed PY-2514 False positive for augmented assignment --- .../inspections/PyAugmentAssignmentInspection.java | 13 ++++++++----- .../PyAugmentAssignmentInspection/test.py | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java index abb92ff419a8..5a7383a1d72e 100644 --- a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java @@ -2,6 +2,7 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.tree.TokenSet; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.actions.AugmentedAssignmentQuickFix; @@ -43,17 +44,19 @@ public class PyAugmentAssignmentInspection extends PyInspection { PyExpression leftExpression = expression.getLeftExpression(); PyExpression rightExpression = expression.getRightExpression(); if (rightExpression != null) { + boolean changedParts = false; if (rightExpression.getText().equals(target.getText())) { PyExpression tmp = rightExpression; rightExpression = leftExpression; leftExpression = tmp; + changedParts = true; } PyElementType op = expression.getOperator(); - if (PyTokenTypes.ADDITIVE_OPERATIONS.contains(op) || - PyTokenTypes.MULTIPLICATIVE_OPERATIONS.contains(op) || - PyTokenTypes.SHIFT_OPERATIONS.contains(op) || - PyTokenTypes.BITWISE_OPERATIONS.contains(op) || - op == PyTokenTypes.EXP) { + final TokenSet operations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MINUS, PyTokenTypes.MULT, + PyTokenTypes.FLOORDIV, PyTokenTypes.DIV, PyTokenTypes.PERC, PyTokenTypes.AND, PyTokenTypes.OR, + PyTokenTypes.XOR, PyTokenTypes.LTLT, PyTokenTypes.GTGT, PyTokenTypes.EXP); + final TokenSet commutativeOperations = TokenSet.create(PyTokenTypes.PLUS, PyTokenTypes.MULT); + if ((operations.contains(op) && !changedParts) || (changedParts && commutativeOperations.contains(op))) { if (leftExpression != null && (leftExpression instanceof PyReferenceExpression || leftExpression instanceof PySubscriptionExpression)) { if (leftExpression.getText().equals(target.getText())) { diff --git a/python/testData/inspections/PyAugmentAssignmentInspection/test.py b/python/testData/inspections/PyAugmentAssignmentInspection/test.py index 50601231ca12..fc807600fb9d 100644 --- a/python/testData/inspections/PyAugmentAssignmentInspection/test.py +++ b/python/testData/inspections/PyAugmentAssignmentInspection/test.py @@ -25,3 +25,6 @@ var_7 += 2 x = x | 3 x = x & 3 x = x ^ 3 + +#PY-2514 +dy = 1 - dy From e00afc8757c35a92315c3fd10d72220c176bfdf6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 15:55:46 +0300 Subject: [PATCH 03/10] fixed PY-2519 Join 2 ifs: disable intention if nested if contains also elif/else clause --- .../python/codeInsight/intentions/PyJoinIfIntention.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 545c84d98621..58187c43589b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -37,10 +37,13 @@ public class PyJoinIfIntention extends BaseIntentionAction { PyIfStatement expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyIfStatement.class); + PyIfStatement ifStatement = getIfStatement(expression); PyStatement firstStatement = getFirstStatement(ifStatement); if (firstStatement != null) { + if (((PyIfStatement)firstStatement).getElifParts().length != 0) return false; + if (((PyIfStatement)firstStatement).getElsePart() != null) return false; PyStatementList stList = ((PyIfStatement)firstStatement).getIfPart().getStatementList(); if (stList != null) if (stList.getStatements().length != 0) From 94c9edc22ce2e596c59d4e153e6b44f6c31f067b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 16 Dec 2010 17:59:40 +0300 Subject: [PATCH 04/10] monokai color scheme for PyCharm, converted by https://github.com/yole/colorSchemeTool --- .../com/jetbrains/python/PythonBundledColorSchemeProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java b/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java index 7b78adb700f3..b852b3d4ecdf 100644 --- a/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java +++ b/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java @@ -13,6 +13,7 @@ public class PythonBundledColorSchemeProvider implements BundledColorSchemesProv public static final String[] PATHS = { "/colorSchemes/WarmNeon", + "/colorSchemes/monokai" }; @Override From 716f337c4f869e42b1d669e361e12cd604d30a43 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 16 Dec 2010 18:17:29 +0300 Subject: [PATCH 05/10] partly fixed PY-2518 Join 2 ifs: merge comments if both presented (Still have problem if comment is on the same level as Statement List) --- .../intentions/PyJoinIfIntention.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 58187c43589b..42636f1f993f 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -3,6 +3,8 @@ package com.jetbrains.python.codeInsight.intentions; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -11,6 +13,8 @@ import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * User: catherine * Intention to merge the if clauses in the case of nested ifs where only the inner if contains code (the outer if only contains the inner one) @@ -62,11 +66,21 @@ public class PyJoinIfIntention extends BaseIntentionAction { if (firstStatement != null && firstStatement instanceof PyIfStatement) { PyExpression condition = ((PyIfStatement)firstStatement).getIfPart().getCondition(); PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); - PyExpression newCondition = elementGenerator.createExpressionFromText(ifStatement.getIfPart().getCondition().getText() + " and " + condition.getText()); + PyExpression newCondition = elementGenerator.createExpressionFromText( + ifStatement.getIfPart().getCondition().getText() + " and " + condition.getText()); ifStatement.getIfPart().getCondition().replace(newCondition); PyStatementList stList = ((PyIfStatement)firstStatement).getIfPart().getStatementList(); PyStatementList ifStatementList = ifStatement.getIfPart().getStatementList(); + + List comments = PsiTreeUtil.getChildrenOfTypeAsList(ifStatement.getIfPart(), PsiComment.class); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(((PyIfStatement)firstStatement).getIfPart(), PsiComment.class)); + + for (PsiElement comm : comments) { + ifStatement.getIfPart().addBefore(comm, ifStatementList); + comm.delete(); + } + ifStatementList.replace(stList); } } From 90a176758320485c69301069e2a0a1eae7192cd3 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 16 Dec 2010 18:45:17 +0300 Subject: [PATCH 06/10] twilight color scheme for PyCharm, converted by https://github.com/yole/colorSchemeTool --- .../com/jetbrains/python/PythonBundledColorSchemeProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java b/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java index b852b3d4ecdf..728258a70c93 100644 --- a/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java +++ b/python/src/com/jetbrains/python/PythonBundledColorSchemeProvider.java @@ -13,7 +13,8 @@ public class PythonBundledColorSchemeProvider implements BundledColorSchemesProv public static final String[] PATHS = { "/colorSchemes/WarmNeon", - "/colorSchemes/monokai" + "/colorSchemes/monokai", + "/colorSchemes/twilight", }; @Override From cd1889b6ba5f29de514b62ac6ad040fec6c33479 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 17 Dec 2010 11:39:29 +0300 Subject: [PATCH 07/10] fixed PY-2518 Join 2 ifs: merge comments if both presented --- .../intentions/PyConvertLambdaToFunctionIntention.java | 2 -- .../python/codeInsight/intentions/PyJoinIfIntention.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java index 921b09624481..2797a11f39fe 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java @@ -59,8 +59,6 @@ public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction { functionBuilder.statement("return " + body.getText()); PyFunction function = functionBuilder.buildFunction(project); - - PyFunction parentFunction = PsiTreeUtil.getTopmostParentOfType(lambdaExpression, PyFunction.class); if (parentFunction != null ) { PyClass parentClass = PsiTreeUtil.getTopmostParentOfType(parentFunction, PyClass.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 42636f1f993f..0bf11d123288 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -75,12 +75,13 @@ public class PyJoinIfIntention extends BaseIntentionAction { List comments = PsiTreeUtil.getChildrenOfTypeAsList(ifStatement.getIfPart(), PsiComment.class); comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(((PyIfStatement)firstStatement).getIfPart(), PsiComment.class)); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(ifStatementList, PsiComment.class)); + comments.addAll(PsiTreeUtil.getChildrenOfTypeAsList(stList, PsiComment.class)); for (PsiElement comm : comments) { ifStatement.getIfPart().addBefore(comm, ifStatementList); comm.delete(); } - ifStatementList.replace(stList); } } From 9fb24d3b5da30305f23a74382bb64923b7f65238 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 17 Dec 2010 12:48:19 +0300 Subject: [PATCH 08/10] fixed PY-2511 Dictionary contains duplicate keys - dict constructor uncovered --- .../PyDictDuplicateKeysInspection.java | 81 +++++++++++++++++-- .../PyDictDuplicateKeysInspection/test.py | 9 ++- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java b/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java index 56e90deea0df..20c8f2edda28 100644 --- a/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java @@ -1,20 +1,18 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.util.Pair; -import com.intellij.psi.PsiElement; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiPolyVariantReference; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyBundle; -import com.jetbrains.python.actions.DictCreationQuickFix; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; /** * User: catherine @@ -57,5 +55,74 @@ public class PyDictDuplicateKeysInspection extends PyInspection { } } } + + @Override + public void visitPyCallExpression(PyCallExpression node) { + if (isDict(node)) { + HashSet set = new HashSet(); + PyExpression[] argumentList = node.getArgumentList().getArguments(); + for (PyExpression argument : argumentList) { + if (argument instanceof PyParenthesizedExpression) + argument = ((PyParenthesizedExpression)argument).getContainedExpression(); + if (argument instanceof PySequenceExpression) { + for (PyElement el : ((PySequenceExpression)argument).getElements()) { + String key = getKey(el); + checkKey(key, set, node); + } + } + else { + String key = getKey(argument); + checkKey(key, set, node); + } + } + } + } + + private void checkKey(String key, Set set, PyCallExpression node) { + if (key != null) { + if (set.contains(key)) { + registerProblem(node, "Dictionary contains duplicate keys " + key); + } + set.add(key); + } + } + + @Nullable + private String getKey(PyElement argument) { + if (argument instanceof PyParenthesizedExpression) { + PyExpression expr = ((PyParenthesizedExpression)argument).getContainedExpression(); + if (expr instanceof PyTupleExpression) { + PyElement key = ((PyTupleExpression)expr).getElements()[0]; + if (key instanceof PyStringLiteralExpression) { + return ((PyStringLiteralExpression)key).getStringValue(); + } + else { + return key.getText(); + } + } + } + if (argument instanceof PyKeywordArgument) { + return ((PyKeywordArgument)argument).getKeyword(); + } + return null; + } + + private boolean isDict(PyCallExpression expression) { + String name = expression.getCallee().getText(); + if ("dict".equals(name)) { + PyType type = expression.getType(myTypeEvalContext); + Application application = ApplicationManager.getApplication(); + if (application != null && application.isUnitTestMode()) { + return true; + } + if (type != null) { + if (type.isBuiltin()) { + return true; + } + } + } + return false; + } + } } diff --git a/python/testData/inspections/PyDictDuplicateKeysInspection/test.py b/python/testData/inspections/PyDictDuplicateKeysInspection/test.py index d8a5ace62bce..3fb6c0f73e84 100644 --- a/python/testData/inspections/PyDictDuplicateKeysInspection/test.py +++ b/python/testData/inspections/PyDictDuplicateKeysInspection/test.py @@ -7,4 +7,11 @@ import random def foo(): return random.random() -{foo(): 1, foo():2} +{foo(): 1, foo():2} + +# PY-2511 +dict = dict([('key', 666), ('key', 123)]) +dict = dict((('key', 666), ('key', 123))) +dict = dict((('key', 666), ('k', 123)), key=4) + +dict([('key', 666), ('ky', 123)]) From a7a48cac4137536bcd96352068335dc1432c3217 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 17 Dec 2010 12:51:25 +0300 Subject: [PATCH 09/10] fixed PY-2533 CCE at com.jetbrains.python.codeInsight.intentions.PyDictLiteralFormToConstructorIntention.isAvailable --- .../intentions/PyDictLiteralFormToConstructorIntention.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java index b34b8aa87fb5..492b5fc995f3 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java @@ -41,9 +41,9 @@ public class PyDictLiteralFormToConstructorIntention extends BaseIntentionAction if (elements.length != 0) { for (PyKeyValueExpression element : elements) { PyExpression key = element.getKey(); - if (! (key instanceof PyStringLiteralExpression)) canConvert = false; + if (! (key instanceof PyStringLiteralExpression)) return false; String str = ((PyStringLiteralExpression)key).getStringValue(); - if(Character.isDigit(str.charAt(0))) canConvert = false; + if(Character.isDigit(str.charAt(0))) return false; try { Integer.parseInt(str) ; canConvert = false; From 9955cd4b35f4d47b7dec729aed1a470c082e0d14 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 17 Dec 2010 12:52:06 +0300 Subject: [PATCH 10/10] focuskiller loading fix (IDEA-62107) --- python/build/pycharm.exe4j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/build/pycharm.exe4j b/python/build/pycharm.exe4j index b1e4eed185de..c44b2d0b3375 100644 --- a/python/build/pycharm.exe4j +++ b/python/build/pycharm.exe4j @@ -55,7 +55,9 @@ - + + +