From 0044e6fc551462131fdae9766993b450833983d0 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 3 Dec 2014 13:05:05 +0300 Subject: [PATCH 01/18] diff: select all root nodes by default better fix for e770f02 --- .../openapi/vcs/changes/ui/ChangesTreeList.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java index 56dd73007946..b5a52c700ef0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java @@ -430,7 +430,17 @@ public abstract class ChangesTreeList extends JPanel implements TypeSafeDataP myList.setSelectedIndex(listSelection); myList.ensureIndexIsVisible(listSelection); - if (scrollRow >= 0) { + if (scrollRow == -1) { + TreeNode root = (TreeNode)model.getRoot(); + int childrenCount = root.getChildCount(); + TreePath[] selected = new TreePath[childrenCount]; + for (int i = 0; i < childrenCount; i++) { + TreeNode child = root.getChildAt(i); + // reverse order, because the last one will become "current" node. And we want it to be the first one. + selected[childrenCount - i - 1] = new TreePath(model.getPathToRoot(child)); + } + myTree.setSelectionPaths(selected); + } else { myTree.setSelectionRow(scrollRow); } TreeUtil.showRowCentered(myTree, scrollRow, false); From 10dcabd7a8f5d1295ec462bc39fe1a2bd23a75d8 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 16 Dec 2014 18:51:21 +0300 Subject: [PATCH 02/18] Snapshot of python-skeletons @ 983e594 --- python/helpers/python-skeletons/README.md | 5 +++++ python/helpers/python-skeletons/__builtin__.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/python/helpers/python-skeletons/README.md b/python/helpers/python-skeletons/README.md index 446ad39a7a73..f6f4ebfe221d 100644 --- a/python/helpers/python-skeletons/README.md +++ b/python/helpers/python-skeletons/README.md @@ -67,6 +67,7 @@ should import it explicitly. For example, in a skeleton for the `foo` module: ```python import foo + class C(foo.B): def bar(): """Do bar and return Bar. @@ -144,6 +145,7 @@ class C(object): pass ``` + ### Versioning The recommended way of checking the version of Python is: @@ -151,10 +153,12 @@ The recommended way of checking the version of Python is: ```python import sys + if sys.version_info >= (2, 7) and sys.version_info < (3,): def from_27_until_30(): pass ``` + A skeleton should document the most recently released version of a library. Use deprecation warnings for functions that have been removed from the API. @@ -214,6 +218,7 @@ the skeletons GitHub repository into your PyCharm/IntelliJ config directory: cd git clone https://github.com/JetBrains/python-skeletons.git ``` + where `` is: * PyCharm diff --git a/python/helpers/python-skeletons/__builtin__.py b/python/helpers/python-skeletons/__builtin__.py index afa270ba02b3..478e6c3f61c5 100644 --- a/python/helpers/python-skeletons/__builtin__.py +++ b/python/helpers/python-skeletons/__builtin__.py @@ -427,6 +427,24 @@ class int(object): """ pass + def __eq__(self, y): + return False + + def __ne__(self, y): + return False + + def __lt__(self, y): + return False + + def __gt__(self, y): + return False + + def __le__(self, y): + return False + + def __ge__(self, y): + return False + def __add__(self, y): """Sum of x and y. From 119d7bedcfbebfb2e6db142664575dcc0606d0c0 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 16 Dec 2014 18:53:46 +0300 Subject: [PATCH 03/18] Read skeletons from the config and 'helpers' directories only --- .../codeInsight/userSkeletons/PyUserSkeletonsUtil.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java index 84239ff24384..17a537616f8b 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsUtil.java @@ -15,7 +15,6 @@ */ package com.jetbrains.python.codeInsight.userSkeletons; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; @@ -24,7 +23,6 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -65,9 +63,7 @@ public class PyUserSkeletonsUtil { private static List getPossibleUserSkeletonsPaths() { final List result = new ArrayList(); result.add(PathManager.getConfigPath() + File.separator + USER_SKELETONS_DIR); - result.add(ApplicationManager.getApplication().isInternal() - ? StringUtil.join(new String[]{PythonHelpersLocator.getPythonCommunityPath(), "helpers", USER_SKELETONS_DIR}, File.separator) - : PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR)); + result.add(PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR)); return result; } From d52beafeba4a8eff4f9cea162c910cb6767dde3b Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Tue, 16 Dec 2014 18:55:59 +0300 Subject: [PATCH 04/18] Fixed checking 'int' against comparison operators in structural type Previosly we collected only atttributes defined in the class and its ancestors. Now we collect attributes defined by class members providers as well. Since comparison operators for 'int' in Python 2 are defined in user skeletons, they used to be unavailable for the attributes search. --- .../inspections/PyTypeCheckerInspection.java | 6 ++-- .../python/psi/types/PyTypeChecker.java | 29 +++++++++++++++---- .../ComparisonOperatorsForNumericTypes.py | 8 +++++ .../PyTypeCheckerInspectionTest.java | 4 +++ 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 python/testData/inspections/PyTypeCheckerInspection/ComparisonOperatorsForNumericTypes.py diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 50230b05c795..4de73fbc47e0 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -133,7 +133,7 @@ public class PyTypeCheckerInspection extends PyInspection { String msg= String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName); if (expected instanceof PyStructuralType) { final Set expectedAttributes = ((PyStructuralType)expected).getAttributeNames(); - final Set actualAttributes = getAttributes(actual); + final Set actualAttributes = getAttributes(actual, context); if (actualAttributes != null) { final Sets.SetView missingAttributes = Sets.difference(expectedAttributes, actualAttributes); if (missingAttributes.size() == 1) { @@ -160,12 +160,12 @@ public class PyTypeCheckerInspection extends PyInspection { } @Nullable - private static Set getAttributes(@NotNull PyType type) { + private static Set getAttributes(@NotNull PyType type, @NotNull TypeEvalContext context) { if (type instanceof PyStructuralType) { return ((PyStructuralType)type).getAttributeNames(); } else if (type instanceof PyClassType) { - return PyTypeChecker.getClassAttributes(((PyClassType)type).getPyClass(), true); + return PyTypeChecker.getClassTypeAttributes((PyClassType)type, true, context); } return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index d5c75466ddd0..7acdb114b036 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -15,11 +15,13 @@ */ package com.jetbrains.python.psi.types; +import com.intellij.openapi.extensions.Extensions; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; import com.jetbrains.python.PyNames; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.resolve.PyResolveContext; @@ -167,15 +169,15 @@ public class PyTypeChecker { return expectedStructural.getAttributeNames().containsAll(actualStructural.getAttributeNames()); } if (expected instanceof PyStructuralType && actual instanceof PyClassType) { - final PyClass cls = ((PyClassType)actual).getPyClass(); - if (overridesGetAttr(cls, context)) { + final PyClassType actualClassType = (PyClassType)actual; + if (overridesGetAttr(actualClassType.getPyClass(), context)) { return true; } - final Set actualAttributes = getClassAttributes(cls, true); + final Set actualAttributes = getClassTypeAttributes(actualClassType, true, context); return actualAttributes.containsAll(((PyStructuralType)expected).getAttributeNames()); } if (actual instanceof PyStructuralType && expected instanceof PyClassType) { - final Set expectedAttributes = getClassAttributes(((PyClassType)expected).getPyClass(), true); + final Set expectedAttributes = getClassTypeAttributes((PyClassType)expected, true, context); return expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames()); } if (actual instanceof PyCallableType && expected instanceof PyCallableType) { @@ -205,7 +207,19 @@ public class PyTypeChecker { } @NotNull - public static Set getClassAttributes(@NotNull PyClass cls, boolean inherited) { + public static Set getClassTypeAttributes(@NotNull PyClassType type, boolean inherited, @NotNull TypeEvalContext context) { + final Set attributes = getClassAttributes(type.getPyClass(), inherited, context); + for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { + final Collection members = provider.getMembers(type, null); + for (PyCustomMember member : members) { + attributes.add(member.getName()); + } + } + return attributes; + } + + @NotNull + private static Set getClassAttributes(@NotNull PyClass cls, boolean inherited, @NotNull TypeEvalContext context) { final Set attributes = new HashSet(); for (PyFunction function : cls.getMethods(false)) { attributes.add(function.getName()); @@ -218,7 +232,10 @@ public class PyTypeChecker { } if (inherited) { for (PyClass ancestor : cls.getAncestorClasses()) { - attributes.addAll(getClassAttributes(ancestor, false)); + final PyType ancestorType = context.getType(ancestor); + if (ancestorType instanceof PyClassType) { + attributes.addAll(getClassTypeAttributes((PyClassType)ancestorType, false, context)); + } } } return attributes; diff --git a/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperatorsForNumericTypes.py b/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperatorsForNumericTypes.py new file mode 100644 index 000000000000..aa460f2a804d --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/ComparisonOperatorsForNumericTypes.py @@ -0,0 +1,8 @@ +def f(x): + print(x < 0, x <= 0, x > 0, x >= 0, x != 0) + print(x.foo) + + +print(f(True)) +print(f(0)) +print(f(3.14)) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 3445236b0139..4bf051596378 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -267,4 +267,8 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { public void testGetAttributeAgainstStructuralType() { doTest(); } + + public void testComparisonOperatorsForNumericTypes() { + doTest(); + } } From 0b089ed2653d8e9229a8c57cf411e5a5a2611403 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 16 Dec 2014 19:17:19 +0300 Subject: [PATCH 05/18] a test case for range marker invalidation failure --- .../intellij/openapi/editor/impl/RangeMarkerTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java index d11847af849a..6447a08f7a52 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/RangeMarkerTest.java @@ -1040,6 +1040,17 @@ public class RangeMarkerTest extends LightPlatformTestCase { assertTrue(marker.isValid()); } + public void testPersistentMarkerDoesntImpactNormalMarkers() { + Document doc = new DocumentImpl("text"); + RangeMarker normal = doc.createRangeMarker(1, 3); + RangeMarker persistent = doc.createRangeMarker(1, 3, true); + + doc.replaceString(0, 4, "before\ntext\nafter"); + + assertTrue(persistent.isValid()); + assertFalse(normal.isValid()); + } + public void testMoveTextRetargetsMarkers() throws Exception { RangeMarkerEx marker1 = createMarker("01234567890", 1, 3); DocumentEx document = (DocumentEx)marker1.getDocument(); From 1089eca2ace9184d47da84ef25e1411e93bfb72e Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 16 Dec 2014 17:18:27 +0100 Subject: [PATCH 06/18] problem with suggesting patch when eap channel and release channel builds are available --- .../updateSettings/impl/BuildInfo.java | 8 +++- .../updateSettings/impl/UpdateStrategy.java | 6 ++- .../ide/updates/UpdateStrategyTest.java | 12 ++++++ .../ide/updates/idea-patchAvailable.xml | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 platform/platform-tests/testSrc/com/intellij/ide/updates/idea-patchAvailable.xml diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/BuildInfo.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/BuildInfo.java index 9b8885aa5cef..4beaf82778d7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/BuildInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/BuildInfo.java @@ -101,9 +101,13 @@ public class BuildInfo implements Comparable { @Nullable public PatchInfo findPatchForCurrentBuild() { - BuildNumber currentBuild = ApplicationInfo.getInstance().getBuild(); + return findPatchForBuild(ApplicationInfo.getInstance().getBuild()); + } + + @Nullable + public PatchInfo findPatchForBuild(BuildNumber currentBuild) { for (PatchInfo each : myPatches) { - if (each.isAvailable() && each.getFromBuild().asStringWithoutProductCode().equals(currentBuild.asStringWithoutProductCode())) + if (each.isAvailable() && each.getFromBuild().asStringWithoutProductCode().equals(currentBuild.asStringWithoutProductCode())) return each; } return null; diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.java index e29c2c6bf715..399168ab35e2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.java @@ -89,7 +89,11 @@ public class UpdateStrategy { for (UpdateChannel channel : channels) { if ((channel.getMajorVersion() == myMajorVersion && channel.getStatus().compareTo(myChannelStatus) >= 0) || (channel.getMajorVersion() > myMajorVersion && channel.getStatus() == ChannelStatus.EAP && myChannelStatus == ChannelStatus.EAP)) { - result.add(channel); + if (channel.getMajorVersion() == myMajorVersion && channel.getStatus().compareTo(myChannelStatus) == 0) { + result.add(0, channel); // prefer channel that has same status as our selected channel status + } else { + result.add(channel); + } } } return result; diff --git a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.java b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.java index c287b32ad172..ab7217ea85c9 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.java @@ -116,4 +116,16 @@ public class UpdateStrategyTest extends TestCase { Assert.assertEquals("IDEA10EAP", newChannel.getId()); Assert.assertEquals("IntelliJ IDEA X EAP", newChannel.getName()); } + + public void testChannelWithCurrentStatusPreferred() { + final TestUpdateSettings settings = new TestUpdateSettings(ChannelStatus.EAP); + + BuildNumber currentBuild = BuildNumber.fromString("IU-139.658"); + UpdateStrategy strategy = new UpdateStrategy(14, currentBuild, UpdatesInfoXppParserTest.InfoReader.read("idea-patchAvailable.xml"), settings); + + final CheckForUpdateResult result = strategy.checkForUpdates(); + Assert.assertEquals(UpdateStrategy.State.LOADED, result.getState()); + Assert.assertEquals(result.getUpdatedChannel().getStatus(), ChannelStatus.EAP); + Assert.assertNotNull(result.getNewBuildInSelectedChannel().findPatchForBuild(currentBuild)); + } } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/updates/idea-patchAvailable.xml b/platform/platform-tests/testSrc/com/intellij/ide/updates/idea-patchAvailable.xml new file mode 100644 index 000000000000..ee7aec67ac17 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/ide/updates/idea-patchAvailable.xml @@ -0,0 +1,37 @@ + + + IU + IC + + + + IntelliJ IDEA 14.0.2 build 139.659 is available. +