From 174ee5a42faf5fc9776d555ef6a87b1979b4a788 Mon Sep 17 00:00:00 2001 From: Aleksey Rostovskiy Date: Tue, 13 Feb 2018 19:35:58 +0300 Subject: [PATCH 01/67] Update com.jetbrains.python.envs version to 0.0.22 --- python/setup-test-environment/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup-test-environment/build.gradle b/python/setup-test-environment/build.gradle index 9d62219a26dd..73608d42be8d 100644 --- a/python/setup-test-environment/build.gradle +++ b/python/setup-test-environment/build.gradle @@ -4,7 +4,7 @@ import java.nio.file.Files import java.nio.file.Paths plugins { - id "com.jetbrains.python.envs" version "0.0.21" + id "com.jetbrains.python.envs" version "0.0.22" } /** From 9809e88aa91c1d2d877d05357b96141c65f8ec37 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 12 Feb 2018 19:15:59 +0100 Subject: [PATCH 02/67] make IG test light --- .../NewExceptionWithoutArguments.java | 2 +- .../expected.xml | 11 ----------- ...ExceptionWithoutArgumentsInspectionTest.java | 17 ++++++++++++----- 3 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java index f563cab3b3c1..bbe52a55c2a9 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java @@ -3,7 +3,7 @@ package com.siyeh.igtest.errorhandling.new_exception_without_arguments; class NewExceptionWithoutArguments { void foo() { - throw new RuntimeException(); + throw new RuntimeException(); } void bar() { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml deleted file mode 100644 index 3d60c6a05598..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - NewExceptionWithoutArguments.java - 6 - Exception constructor called without arguments - <code>new RuntimeException()</code> without arguments #loc - - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java index a2c90da22966..764991a86ca5 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java @@ -1,12 +1,19 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.errorhandling; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class NewExceptionWithoutArgumentsInspectionTest extends IGInspectionTestCase { +public class NewExceptionWithoutArgumentsInspectionTest extends LightInspectionTestCase { - public void test() { - final NewExceptionWithoutArgumentsInspection tool = new NewExceptionWithoutArgumentsInspection(); - doTest("com/siyeh/igtest/errorhandling/new_exception_without_arguments", tool); + public void testNewExceptionWithoutArguments() { + doTest(); } + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new NewExceptionWithoutArgumentsInspection(); + } } From 5a852fd7140466de8b6251792c4f633166d801d6 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 12 Feb 2018 20:21:55 +0100 Subject: [PATCH 03/67] make IG test light --- .../ImplicitArrayToString.java | 25 +++--- .../implicit_array_to_string/expected.xml | 83 ------------------- .../ImplicitArrayToStringInspectionTest.java | 41 +++++++-- 3 files changed, 47 insertions(+), 102 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/expected.xml diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/ImplicitArrayToString.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/ImplicitArrayToString.java index 7a6be2a9cb40..741ff3e8d28a 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/ImplicitArrayToString.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/ImplicitArrayToString.java @@ -3,19 +3,16 @@ package com.siyeh.igtest.bugs.implicit_array_to_string; import java.io.PrintWriter; import java.util.Formatter; - - - public class ImplicitArrayToString { void foo() { String[] interfaces = {"java/util/Set", "java/util/List"}; - System.out.println("interfaces: " + interfaces); // triggered + System.out.println("interfaces: " + interfaces); // triggered System.out.printf("interfaces: %s\n", interfaces); // not triggered - System.out.printf("interfaces: %s, count: %s", interfaces, "2"); + System.out.printf("interfaces: %s, count: %s", interfaces, "2"); String.format("interfaces: %s\n", interfaces); - String.format("interfaces: %s, count: %s", interfaces, "2"); - new Formatter().format("interfaces: %s\n", interfaces); + String.format("interfaces: %s, count: %s", interfaces, "2"); + new Formatter().format("interfaces: %s\n", interfaces); new PrintWriter(System.out).format("interfaces: %s\n", interfaces); } @@ -26,7 +23,7 @@ public class ImplicitArrayToString { } private String bar(int[] array) { - return String.valueOf(array) + array.toString(); + return String.valueOf(array) + array.toString(); } private void noWarnOnCharArrays(char[] cs) { @@ -35,14 +32,14 @@ public class ImplicitArrayToString { } private void warnOnStringBuilderAppend(int[] is) { - new StringBuilder().append(is); // calls String.valueOf + new StringBuilder().append(is); // calls String.valueOf } void foo2() { - System.out.println("new String[10]" + new String[10]); + System.out.println("new String[10]" + new String[10]); final String[] var = new String[10]; - System.out.println("new String[10]" + var); - System.out.println("new String[10]" + meth()); + System.out.println("new String[10]" + var); + System.out.println("new String[10]" + meth()); } private String[] meth() { @@ -52,10 +49,10 @@ public class ImplicitArrayToString { public static void main(String[] args) { char[] charArray = new char[]{'A', 'B', 'C'}; System.out.println(charArray); // should not warn - System.out.println(args); // should indeed warn + System.out.println(args); // should indeed warn } void concatenation(int[] is) { - String s = "string" + is + "string"; + String s = "string" + is + "string"; } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/expected.xml deleted file mode 100644 index 5aba5b469e34..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/implicit_array_to_string/expected.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - ImplicitArrayToString.java - 13 - Implicit call to array '.toString()' - Implicit call to 'toString()' on array <code>interfaces</code> - - - - - ImplicitArrayToString.java - 15 - Implicit call to array '.toString()' - Implicit call to 'toString()' on array <code>interfaces</code> - - - - - ImplicitArrayToString.java - 17 - Implicit call to array '.toString()' - Implicit call to 'toString()' on array <code>interfaces</code> - - - - ImplicitArrayToString.java - 29 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>array</code> #loc - - - - ImplicitArrayToString.java - 29 - Call to 'toString()' on array - Call to 'toString()' on array #loc - - - - ImplicitArrayToString.java - 38 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>is</code> #loc - - - - ImplicitArrayToString.java - 42 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>new String[10]</code> #loc - - - - - ImplicitArrayToString.java - 44 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>var</code> #loc - - - - - ImplicitArrayToString.java - 45 - Call to 'toString()' on array - Implicit call to 'toString()' on array returned by call to <code>meth()</code> #loc - - - - ImplicitArrayToString.java - 55 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>args</code> #loc - - - - ImplicitArrayToString.java - 59 - Call to 'toString()' on array - Implicit call to 'toString()' on array <code>is</code> #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ImplicitArrayToStringInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ImplicitArrayToStringInspectionTest.java index 16a22226a77e..4a197aeb4cc3 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ImplicitArrayToStringInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ImplicitArrayToStringInspectionTest.java @@ -1,11 +1,42 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.bugs; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class ImplicitArrayToStringInspectionTest extends IGInspectionTestCase { +public class ImplicitArrayToStringInspectionTest extends LightInspectionTestCase { - public void test() { - doTest("com/siyeh/igtest/bugs/implicit_array_to_string", - new ImplicitArrayToStringInspection()); + public void testImplicitArrayToString() { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new ImplicitArrayToStringInspection(); + } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package java.util;" + + "public class Formatter {" + + " public Formatter format(Locale l, String format, Object ... args) {" + + " return null;" + + " }" + + " public Formatter format(String format, Object ... args) {" + + " return null;" + + " }" + + "}", + + "package java.io;" + + "public class PrintWriter extends Writer {" + + " public PrintWriter(OutputStream out) {}" + + " public PrintWriter format(String format, Object ... args) {" + + " return null;" + + " }" + + "}" + }; } } \ No newline at end of file From fa2ea2cf4986489cbd1679d7763ffb147a1390be Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 13 Feb 2018 14:25:28 +0100 Subject: [PATCH 04/67] SSR: wording --- platform/structuralsearch/source/messages/SSRBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/structuralsearch/source/messages/SSRBundle.properties b/platform/structuralsearch/source/messages/SSRBundle.properties index 4534540022af..51599ae91ef6 100644 --- a/platform/structuralsearch/source/messages/SSRBundle.properties +++ b/platform/structuralsearch/source/messages/SSRBundle.properties @@ -247,7 +247,7 @@ groovy.script.error=Groovy Script execution error: {0} template.problem=Structural Search Inspection problem in template ''{0}'' problem=Structural Search problem: {0} complete.match.variable.name=Complete Match -predefined.configuration.sample.method.invokation.with.constant.argument=sample method invocation with constant parameter +predefined.configuration.sample.method.invokation.with.constant.argument=sample method invocation with constant argument predefined.configuration.interfaces.having.no.descendants=interface that is not implemented or extended predefined.configuration.enums=enums regular.expression.help.label=Regular Expressions Help From e18c2f713c8e146193d08b948625e673a005c884 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 13 Feb 2018 17:19:39 +0100 Subject: [PATCH 05/67] SSR: don't silently ignore invalid part of pattern --- .../JavaStructuralSearchProfile.java | 64 +++++++++---------- .../StructuralSearchTest.java | 13 +++- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 12a39f8841bf..883f2de8f4a7 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -245,34 +245,34 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); if (context == PatternTreeContext.Block) { final PsiCodeBlock codeBlock = elementFactory.createCodeBlockFromText("{\n" + text + "\n}", null); - final PsiElement[] children = codeBlock.getChildren(); - final int extraChildCount = 4; + PsiElement element = codeBlock.getFirstBodyElement(); + if (element == null) return PsiElement.EMPTY_ARRAY; + final List result = new SmartList<>(); + final PsiElement lastBodyElement = codeBlock.getLastBodyElement(); + while (element != null) { + if (!(element instanceof PsiWhiteSpace)) result.add(element); + if (element == lastBodyElement) break; + element = element.getNextSibling(); + } + if (result.isEmpty()) return PsiElement.EMPTY_ARRAY; - if (children.length > extraChildCount) { - PsiElement[] result = new PsiElement[children.length - extraChildCount]; - System.arraycopy(children, 2, result, 0, children.length - extraChildCount); - - if (shouldTryExpressionPattern(result)) { - try { - final PsiElement[] expressionPattern = - createPatternTree(text, PatternTreeContext.Expression, fileType, language, contextName, extension, project, false); - if (expressionPattern.length == 1) { - result = expressionPattern; - } - } catch (IncorrectOperationException ignore) {} - } - else if (shouldTryClassPattern(result)) { - final PsiElement[] classPattern = - createPatternTree(text, PatternTreeContext.Class, fileType, language, contextName, extension, project, false); - if (classPattern.length == 1) { - result = classPattern; + if (shouldTryExpressionPattern(result)) { + try { + final PsiElement[] expressionPattern = + createPatternTree(text, PatternTreeContext.Expression, fileType, language, contextName, extension, project, false); + if (expressionPattern.length == 1) { + return expressionPattern; } + } catch (IncorrectOperationException ignore) {} + } + else if (shouldTryClassPattern(result)) { + final PsiElement[] classPattern = + createPatternTree(text, PatternTreeContext.Class, fileType, language, contextName, extension, project, false); + if (classPattern.length == 1) { + return classPattern; } - return result; - } - else { - return PsiElement.EMPTY_ARRAY; } + return result.toArray(PsiElement.EMPTY_ARRAY); } else if (context == PatternTreeContext.Class) { final PsiClass clazz = elementFactory.createClassFromText(text, null); @@ -300,9 +300,9 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } - private static boolean shouldTryExpressionPattern(PsiElement[] elements) { - if (elements.length >= 1 && elements.length <= 3) { - final PsiElement firstElement = elements[0]; + private static boolean shouldTryExpressionPattern(List elements) { + if (elements.size() >= 1 && elements.size() <= 3) { + final PsiElement firstElement = elements.get(0); if (firstElement instanceof PsiDeclarationStatement) { final PsiElement lastChild = firstElement.getLastChild(); if (lastChild instanceof PsiErrorElement && PsiTreeUtil.prevLeaf(lastChild) instanceof PsiErrorElement) { @@ -316,13 +316,13 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { return false; } - private static boolean shouldTryClassPattern(PsiElement[] elements) { - if (elements.length < 2) { + private static boolean shouldTryClassPattern(List elements) { + if (elements.size() < 2) { return false; } - final PsiElement firstElement = elements[0]; - final PsiElement secondElement = elements[1]; - final PsiElement lastElement = elements[elements.length - 1]; + final PsiElement firstElement = elements.get(0); + final PsiElement secondElement = elements.get(1); + final PsiElement lastElement = elements.get(elements.size() - 1); if (firstElement instanceof PsiDocComment) { // might be method with javadoc diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 279205ae0a53..b4e92db25c3a 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -2345,6 +2345,11 @@ public class StructuralSearchTest extends StructuralSearchTestCase { fail("malformed pattern warning expected"); } catch (MalformedPatternException ignored) {} + findMatchesCount(source, "'_ReturnType '_Method*('_ParameterType '_Parameter);"); + } + + public void testInvalidPatternWarnings() { + final String source = "{}"; try { findMatchesCount(source, "import java.util.ArrayList;"); fail("malformed pattern warning expected"); @@ -2361,11 +2366,15 @@ public class StructuralSearchTest extends StructuralSearchTestCase { } catch (MalformedPatternException ignored) {} try { - findMatchesCount(s4, "0x100000000"); + findMatchesCount(source, "0x100000000"); fail("malformed pattern warning expected"); } catch (MalformedPatternException ignored) {} - findMatchesCount(source, "'_ReturnType '_Method*('_ParameterType '_Parameter);"); + try { + findMatchesCount(source, "assert '_C;\n" + + "System.out.println("); + fail("malformed pattern warning expected"); + } catch (MalformedPatternException ignored) {} } public void testFindInnerClass() { From b19b8b7b0f99eaabea26b048ccab2945146c6ddd Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 13 Feb 2018 17:36:04 +0100 Subject: [PATCH 06/67] SSR: fix "can't replace expressions with statements" warning and reverse --- .../intellij/structuralsearch/JavaStructuralSearchProfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 883f2de8f4a7..5db6d74c96b9 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -437,7 +437,7 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { boolean targetFound = false; for (final String name : matchOptions.getVariableConstraintNames()) { final MatchVariableConstraint constraint = matchOptions.getVariableConstraint(name); - if (constraint.isPartOfSearchResults()) { + if (constraint.isPartOfSearchResults() && !Configuration.CONTEXT_VAR_NAME.equals(constraint.getName())) { targetFound = true; break; } From 81dd51f5681fb9041b9f0bea60770156a10b82a8 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 13 Feb 2018 17:37:12 +0100 Subject: [PATCH 07/67] SSR: don't compile in the swing event thread (IDEA-186640) --- .../plugin/ui/SearchDialog.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchDialog.java index d903d2bb83e1..971546fe6992 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/SearchDialog.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.structuralsearch.plugin.ui; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; @@ -9,6 +9,8 @@ import com.intellij.ide.IdeBundle; import com.intellij.ide.util.scopeChooser.ScopeChooserCombo; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -115,7 +117,7 @@ public class SearchDialog extends DialogWrapper { myConfiguration = createConfiguration(null); init(); - myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myDisposable); + myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, myDisposable); } public void setUseLastConfiguration(boolean useLastConfiguration) { @@ -160,16 +162,20 @@ public class SearchDialog extends DialogWrapper { void initiateValidation() { myAlarm.cancelAllRequests(); myAlarm.addRequest(() -> { - try { - getOKAction().setEnabled(isValid()); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (RuntimeException e) { - Logger.getInstance(SearchDialog.class).error(e); - } - }, 500); + final boolean valid = ReadAction.compute(() -> { + try { + return Boolean.valueOf(isValid()); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (RuntimeException e) { + Logger.getInstance(SearchDialog.class).error(e); + } + return Boolean.FALSE; + }).booleanValue(); + ApplicationManager.getApplication().invokeLater(() -> getOKAction().setEnabled(valid)); + }, 250); } protected void buildOptions(JPanel searchOptions) { @@ -704,6 +710,9 @@ public class SearchDialog extends DialogWrapper { return myConfiguration; } + /** + * Needs to be called on the event thread or while holding a read lock. + */ protected boolean isValid() { try { Matcher.validate(searchContext.getProject(), getConfiguration().getMatchOptions()); From 0dfb84b8adee4b6dd5679b5452ad3485f8d58d69 Mon Sep 17 00:00:00 2001 From: Sergey Karashevich Date: Tue, 13 Feb 2018 17:30:42 +0300 Subject: [PATCH 08/67] [gui-test] fix transient fatal errors GUI-76 --- .../testGuiFramework/framework/GuiTestRunner.kt | 2 +- .../com/intellij/testGuiFramework/impl/GuiTestRule.kt | 11 ++++------- .../testGuiFramework/remote/JUnitClientListener.kt | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/framework/GuiTestRunner.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/framework/GuiTestRunner.kt index c040dadad0ae..4c44550fc2f7 100755 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/framework/GuiTestRunner.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/framework/GuiTestRunner.kt @@ -146,7 +146,7 @@ class GuiTestRunner internal constructor(val runner: GuiTestRunnerInterface) { val runListener: RunListener = object : RunListener() { override fun testFailure(failure: Failure?) { - LOG.error("Test failed: '$testName'") + LOG.info("Test failed: '$testName'") notifier.removeListener(this) super.testFailure(failure) } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt index 78a2b4832853..07f02fde29e6 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestRule.kt @@ -40,6 +40,7 @@ import com.intellij.testGuiFramework.impl.GuiTestUtilKt.runOnEdt import com.intellij.testGuiFramework.impl.GuiTestUtilKt.waitUntil import com.intellij.testGuiFramework.util.Key import com.intellij.ui.Splash +import com.intellij.util.concurrency.AppExecutorUtil import org.fest.swing.core.Robot import org.fest.swing.exception.ComponentLookupException import org.fest.swing.exception.WaitTimedOutError @@ -72,7 +73,6 @@ class GuiTestRule : TestRule { private var myProjectPath: File? = null set private var myTestName: String = "undefined" - private var currentTestErrors = 0 private var currentTestDateStart: Date = Date() private val myRuleChain = RuleChain.emptyRuleChain() @@ -112,7 +112,6 @@ class GuiTestRule : TestRule { errors.addAll(tearDown()) // shouldn't throw, but called inside a try-finally for defense in depth } finally { - currentTestErrors = errors.size //noinspection ThrowFromFinallyBlock; assertEmpty is intended to throw here MultipleFailureException.assertEmpty(errors) } @@ -230,11 +229,9 @@ class GuiTestRule : TestRule { override fun after() { try { - if (currentTestErrors > 0) { - GuiTestUtilKt.waitUntil("fatal errors in message log will sync") { - MessagePool.getInstance().getFatalErrors(true, true).size >= currentTestErrors - } - } + val executorService = AppExecutorUtil.getAppExecutorService() + //wait 10 second for the termination of all + if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) executorService.shutdownNow() MessagePool.getInstance().clearFatals() } catch (e: Exception) { diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/remote/JUnitClientListener.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/remote/JUnitClientListener.kt index c961f151a9c2..04e4cc6b976e 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/remote/JUnitClientListener.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/remote/JUnitClientListener.kt @@ -44,7 +44,6 @@ class JUnitClientListener(val sendObjectFun: (JUnitInfo) -> Unit) : RunListener( override fun testFailure(failure: Failure?) { sendObjectFun(JUnitInfo(Type.FAILURE, failure!!.exception, JUnitInfo.getClassAndMethodName(failure.description))) - LOG.error(failure.exception) } override fun testFinished(description: Description?) { From 54c796825ce2bdefb6811b1850ae4acc37ec38a8 Mon Sep 17 00:00:00 2001 From: Sergey Karashevich Date: Tue, 13 Feb 2018 17:31:42 +0300 Subject: [PATCH 09/67] [gui-test] add waiter for Loading Templates progress dialog --- .../testGuiFramework/tests/community/CommandLineProjectTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/CommandLineProjectTest.kt b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/CommandLineProjectTest.kt index 61704f33dca6..16990e831b41 100644 --- a/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/CommandLineProjectTest.kt +++ b/community-guitests/testSrc/com/intellij/testGuiFramework/tests/community/CommandLineProjectTest.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.ui.MultiLineLabelUI import com.intellij.openapi.util.text.StringUtil import com.intellij.testGuiFramework.framework.RunWithIde import com.intellij.testGuiFramework.impl.GuiTestCase +import com.intellij.testGuiFramework.impl.GuiTestUtilKt import com.intellij.testGuiFramework.launcher.ide.CommunityIde import org.junit.Assert.assertTrue import org.junit.Test @@ -46,6 +47,7 @@ public class Main { actionLink("Create New Project").click() dialog("New Project") { jList("Java").clickItem("Java") + GuiTestUtilKt.waitProgressDialogUntilGone(robot(), "Loading Templates") button("Next").click() checkbox("Create project from template").click() jList("Command Line App").clickItem("Command Line App") From 46d876af538bad4664a426217e424410b54498ad Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Tue, 13 Feb 2018 19:57:44 +0300 Subject: [PATCH 10/67] EA-61170 - AIOOBE: DefaultMutableTreeNode.getChildAt --- .../debugger/ui/impl/ThreadsPanel.java | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java index 921123727c4f..fd8a41d595e9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/ThreadsPanel.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.ui.impl; import com.intellij.debugger.actions.DebuggerAction; @@ -40,6 +26,8 @@ import org.jetbrains.annotations.NotNull; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.util.Enumeration; +import java.util.NoSuchElementException; public class ThreadsPanel extends DebuggerTreePanel{ @NonNls private static final String HELP_ID = "debugging.debugThreads"; @@ -138,11 +126,15 @@ public class ThreadsPanel extends DebuggerTreePanel{ } private static void updateNodeLabels(DebuggerTreeNodeImpl from) { - final int childCount = from.getChildCount(); - for (int idx = 0; idx < childCount; idx++) { - final DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)from.getChildAt(idx); - child.getDescriptor().updateRepresentation(null, child::labelChanged); - updateNodeLabels(child); + Enumeration children = from.children(); + try { + while (children.hasMoreElements()) { + DebuggerTreeNodeImpl child = (DebuggerTreeNodeImpl)children.nextElement(); + child.getDescriptor().updateRepresentation(null, child::labelChanged); + updateNodeLabels(child); + } + } + catch (NoSuchElementException ignored) { // children have changed - just skip } } From 572a0a5612d1b8a501e4409eb0003f352595548c Mon Sep 17 00:00:00 2001 From: Konstantin Aleev Date: Tue, 13 Feb 2018 16:17:26 +0300 Subject: [PATCH 11/67] move Update Running Application action to lang-impl --- .../update/RunningApplicationUpdater.java | 21 +++ .../RunningApplicationUpdaterProvider.java | 16 +++ .../UpdateRunningApplicationAction.java | 130 ++++++++++++++++++ .../src/META-INF/LangExtensionPoints.xml | 3 + .../src/idea/LangActions.xml | 6 + .../com/intellij/keymap/KeymapsTestCase.java | 6 +- resources/src/idea/JavaActions.xml | 2 +- 7 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdater.java create mode 100644 platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdaterProvider.java create mode 100644 platform/lang-impl/src/com/intellij/execution/update/UpdateRunningApplicationAction.java diff --git a/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdater.java b/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdater.java new file mode 100644 index 000000000000..5b51162c1fb0 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdater.java @@ -0,0 +1,21 @@ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.execution.update; + +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public interface RunningApplicationUpdater { + String getDescription(); + + String getShortName(); + + @Nullable + Icon getIcon(); + + default boolean isEnabled() { + return true; + } + + void performUpdate(); +} diff --git a/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdaterProvider.java b/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdaterProvider.java new file mode 100644 index 000000000000..5bf1ece22ec3 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/update/RunningApplicationUpdaterProvider.java @@ -0,0 +1,16 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.execution.update; + +import com.intellij.execution.process.ProcessHandler; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface RunningApplicationUpdaterProvider { + ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.runningApplicationUpdaterProvider"); + + @Nullable + RunningApplicationUpdater createUpdater(@NotNull Project project, @NotNull ProcessHandler process); +} diff --git a/platform/lang-impl/src/com/intellij/execution/update/UpdateRunningApplicationAction.java b/platform/lang-impl/src/com/intellij/execution/update/UpdateRunningApplicationAction.java new file mode 100644 index 000000000000..9e945c5625c8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/update/UpdateRunningApplicationAction.java @@ -0,0 +1,130 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.execution.update; + +import com.intellij.execution.ExecutionManager; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.ListPopup; +import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.ui.popup.util.BaseListPopupStep; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class UpdateRunningApplicationAction extends AnAction { + public UpdateRunningApplicationAction() { + super("Update Running Application", null, AllIcons.Javaee.UpdateRunningApplication); + } + + @Override + public void update(AnActionEvent e) { + final Project project = e.getData(CommonDataKeys.PROJECT); + final RunContentDescriptor contentDescriptor = e.getData(LangDataKeys.RUN_CONTENT_DESCRIPTOR); + final Presentation presentation = e.getPresentation(); + if (contentDescriptor != null && project != null) { + final ProcessHandler processHandler = contentDescriptor.getProcessHandler(); + final RunningApplicationUpdater updater = findUpdater(project, processHandler); + if (updater != null) { + presentation.setEnabled(processHandler.isStartNotified() && !processHandler.isProcessTerminating() + && !processHandler.isProcessTerminated() && updater.isEnabled()); + presentation.setText(updater.getDescription()); + } + else { + presentation.setEnabled(false); + } + presentation.setVisible(true); + return; + } + + final List updaters = getAvailableUpdaters(project); + final boolean enable = !updaters.isEmpty(); + presentation.setEnabledAndVisible(enable); + if (updaters.size() == 1) { + presentation.setText(updaters.get(0).getDescription()); + } + else { + presentation.setText("Update Running Application..."); + } + } + + @Nullable + private static RunningApplicationUpdater findUpdater(@NotNull Project project, @Nullable ProcessHandler processHandler) { + if (processHandler == null) return null; + + for (RunningApplicationUpdaterProvider provider : RunningApplicationUpdaterProvider.EP_NAME.getExtensions()) { + final RunningApplicationUpdater updater = provider.createUpdater(project, processHandler); + if (updater != null) { + return updater; + } + } + return null; + } + + private static List getAvailableUpdaters(@Nullable Project project) { + if (project == null) { + return Collections.emptyList(); + } + + List result = new ArrayList<>(); + ProcessHandler[] processes = ExecutionManager.getInstance(project).getRunningProcesses(); + for (ProcessHandler process : processes) { + if (!process.isProcessTerminated() && !process.isProcessTerminating() && process.isStartNotified()) { + ContainerUtil.addIfNotNull(result, findUpdater(project, process)); + } + } + return result; + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project == null) return; + + final RunContentDescriptor contentDescriptor = e.getData(LangDataKeys.RUN_CONTENT_DESCRIPTOR); + if (contentDescriptor != null) { + final RunningApplicationUpdater updater = findUpdater(project, contentDescriptor.getProcessHandler()); + + if (updater != null && updater.isEnabled()) { + updater.performUpdate(); + return; + } + } + + final List updaters = getAvailableUpdaters(project); + if (updaters.isEmpty()) return; + + if (updaters.size() > 1) { + final ListPopup popup = + JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep("Select Process to Update", updaters) { + @NotNull + @Override + public String getTextFor(RunningApplicationUpdater value) { + return value.getShortName(); + } + + @Override + public Icon getIconFor(RunningApplicationUpdater value) { + return value.getIcon(); + } + + @Override + public PopupStep onChosen(final RunningApplicationUpdater selectedValue, boolean finalChoice) { + return doFinalStep(() -> selectedValue.performUpdate()); + } + }); + popup.showCenteredInCurrentWindow(project); + } + else { + updaters.get(0).performUpdate(); + } + } +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 59f1c4588778..8e97875c4ec1 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -925,6 +925,9 @@ beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint"> + + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index ac3684040c63..039e4b0e82cf 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -1082,5 +1082,11 @@ + + + + + diff --git a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java index 9db0356ed679..1acd4b5ec4f0 100644 --- a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java +++ b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java @@ -27,7 +27,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { { "alt UP", "MethodUp", "Arrangement.Rule.Match.Condition.Move.Up"}, { "alt F1", "SelectIn", "ProjectViewChangeView"}, { "alt INSERT", "FileChooser.NewFolder", "Generate", "NewElement"}, - { "control F10", "Android.HotswapChanges", "javaee.UpdateRunningApplication", "liveedit.UpdateRunningApplication"}, + { "control F10", "Android.HotswapChanges", "UpdateRunningApplication"}, { "control 1", "FileChooser.GotoHome", "GotoBookmark1", "DuplicatesForm.SendToLeft"}, { "control 2", "FileChooser.GotoProject", "GotoBookmark2", "DuplicatesForm.SendToRight"}, { "control 3", "GotoBookmark3", "FileChooser.GotoModule"}, @@ -158,7 +158,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { { "alt F8", "ReformatCode", "ForceStepInto", "EvaluateExpression"}, { "control COMMA", "GotoClass", "GotoChangedFile"}, { "control F1", "ExternalJavaDoc", "ShowErrorDescription"}, - { "control F10", "Android.HotswapChanges", "RunToCursor", "javaee.UpdateRunningApplication", "liveedit.UpdateRunningApplication"}, + { "control F10", "Android.HotswapChanges", "RunToCursor", "UpdateRunningApplication"}, { "control N", "FileChooser.NewFolder", "Generate", }, { "control P", "FileChooser.TogglePathShowing", "Print"}, { "control alt F", "ReformatCode", "IntroduceField"}, @@ -193,7 +193,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { { "alt DOWN", "ShowContent", "MoveStatementDown", "Arrangement.Rule.Match.Condition.Move.Down"}, { "alt UP", "MoveStatementUp", "Arrangement.Rule.Match.Condition.Move.Up"}, { "alt HOME", "ViewNavigationBar", "ShowNavBar"}, - { "control F10", "Android.HotswapChanges", "ShowPopupMenu", "javaee.UpdateRunningApplication", "liveedit.UpdateRunningApplication"}, + { "control F10", "Android.HotswapChanges", "ShowPopupMenu", "UpdateRunningApplication"}, { "control D", "EditorDeleteLine", "Diff.ShowDiff", "CompareTwoFiles", "SendEOF", "FileChooser.GotoDesktop"}, { "control L", "Vcs.Log.FocusTextFilter", "GotoLine"}, { "control N", "ShowPopupMenu", "FileChooser.NewFolder"}, diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index eae19984023e..aa2757c37c77 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -107,7 +107,7 @@ - + From ff7da316cf78975f379d797e4daae1e63ede8a29 Mon Sep 17 00:00:00 2001 From: Konstantin Aleev Date: Tue, 13 Feb 2018 16:23:28 +0300 Subject: [PATCH 12/67] add callback for classes hot swapping --- .../debugger/ui/HotSwapProgressImpl.java | 29 ++++++++- .../debugger/ui/HotSwapStatusListener.java | 10 +++ .../com/intellij/debugger/ui/HotSwapUI.java | 7 ++- .../intellij/debugger/ui/HotSwapUIImpl.java | 63 +++++++++++++++++-- 4 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/HotSwapStatusListener.java diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java index ce10b0d03c1d..178089f3268e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapProgressImpl.java @@ -51,7 +51,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -public class HotSwapProgressImpl extends HotSwapProgress{ +public class HotSwapProgressImpl extends HotSwapProgress { static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("HotSwap", ToolWindowId.DEBUG); private final TIntObjectHashMap> myMessages = new TIntObjectHashMap<>(); @@ -59,6 +59,7 @@ public class HotSwapProgressImpl extends HotSwapProgress{ private String myTitle = DebuggerBundle.message("progress.hot.swap.title"); private final MergingUpdateQueue myUpdateQueue; private WeakReference mySessionRef = null; + private List myListeners = ContainerUtil.newSmartList(); public HotSwapProgressImpl(Project project) { super(project); @@ -78,10 +79,22 @@ public class HotSwapProgressImpl extends HotSwapProgress{ myUpdateQueue = new MergingUpdateQueue("HotSwapProgress update queue", 100, true, null, myProgressWindow); } + @Override + public void cancel() { + super.cancel(); + for (HotSwapProgressListener listener : myListeners) { + listener.onCancel(); + } + } + @Override public void finished() { super.finished(); + for (HotSwapProgressListener listener : myListeners) { + listener.onFinish(); + } + List errors = getMessages(MessageCategory.ERROR); List warnings = getMessages(MessageCategory.WARNING); @@ -143,7 +156,7 @@ public class HotSwapProgressImpl extends HotSwapProgress{ mySessionRef = new WeakReference<>(session.getXDebugSession()); } - private List getMessages(int category) { + List getMessages(int category) { return ContainerUtil.notNullize(myMessages.get(category)); } @@ -215,4 +228,16 @@ public class HotSwapProgressImpl extends HotSwapProgress{ myTitle = DebuggerBundle.message("progress.hot.swap.title") + " : " + session.getSessionName(); myProgressWindow.setTitle(myTitle); } + + void addProgressListener(@NotNull HotSwapProgressListener listener) { + myListeners.add(listener); + } + + interface HotSwapProgressListener { + default void onCancel() { + } + + default void onFinish() { + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapStatusListener.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapStatusListener.java new file mode 100644 index 000000000000..568ad11849a1 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapStatusListener.java @@ -0,0 +1,10 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.debugger.ui; + +import com.intellij.debugger.impl.DebuggerSession; + +import java.util.List; + +public interface HotSwapStatusListener { + void hotSwapFinished(boolean aborted, int errors, int warnings, List sessions); +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java index 5cae3a873c8c..fa6e5799da54 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUI.java @@ -18,6 +18,8 @@ package com.intellij.debugger.ui; import com.intellij.openapi.project.Project; import com.intellij.debugger.impl.DebuggerSession; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author nik @@ -27,11 +29,12 @@ public abstract class HotSwapUI { return project.getComponent(HotSwapUI.class); } - public abstract void reloadChangedClasses(DebuggerSession session, boolean compileBeforeHotswap); + public abstract void reloadChangedClasses(@NotNull DebuggerSession session, boolean compileBeforeHotswap); + + public abstract void reloadChangedClasses(@NotNull DebuggerSession session, @Nullable HotSwapStatusListener callback); public abstract void dontPerformHotswapAfterThisCompilation(); - public abstract void addListener(HotSwapVetoableListener listener); public abstract void removeListener(HotSwapVetoableListener listener); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java index c8bd9bceec6b..752c2c77ec96 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/HotSwapUIImpl.java @@ -35,6 +35,7 @@ import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.MessageCategory; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -96,7 +97,8 @@ public class HotSwapUIImpl extends HotSwapUI { return sessions.stream().anyMatch(DebuggerSession::isPaused); } - private void hotSwapSessions(final List sessions, @Nullable final Map> generatedPaths) { + private void hotSwapSessions(final List sessions, @Nullable final Map> generatedPaths, + @Nullable final HotSwapStatusListener callback) { final boolean shouldAskBeforeHotswap = myAskBeforeHotswap; myAskBeforeHotswap = true; @@ -104,7 +106,14 @@ public class HotSwapUIImpl extends HotSwapUI { final String runHotswap = settings.RUN_HOTSWAP_AFTER_COMPILE; final boolean shouldDisplayHangWarning = shouldDisplayHangWarning(settings, sessions); + HotSwapStatusListener callbackWrapper = (aborted, errors, warnings, hotSwappedSessions) -> { + if (callback != null) { + callback.hotSwapFinished(aborted, errors, warnings, hotSwappedSessions); + } + }; + if (shouldAskBeforeHotswap && DebuggerSettings.RUN_HOTSWAP_NEVER.equals(runHotswap)) { + callbackWrapper.hotSwapFinished(true, 0, 0, sessions); return; } @@ -118,6 +127,14 @@ public class HotSwapUIImpl extends HotSwapUI { boolean createProgress = sessions.stream().anyMatch(DebuggerSession::isModifiedClassesScanRequired); findClassesProgress = createProgress ? new HotSwapProgressImpl(myProject) : null; } + if (findClassesProgress != null) { + findClassesProgress.addProgressListener(new HotSwapProgressImpl.HotSwapProgressListener() { + @Override + public void onCancel() { + callbackWrapper.hotSwapFinished(true, 0, 0, sessions); + } + }); + } ApplicationManager.getApplication().executeOnPooledThread(() -> { final Map> modifiedClasses; @@ -144,6 +161,7 @@ public class HotSwapUIImpl extends HotSwapUI { if (modifiedClasses.isEmpty()) { final String message = DebuggerBundle.message("status.hotswap.uptodate"); HotSwapProgressImpl.NOTIFICATION_GROUP.createNotification(message, NotificationType.INFORMATION).notify(myProject); + callbackWrapper.hotSwapFinished(false, 0, 0, sessions); return; } @@ -154,6 +172,7 @@ public class HotSwapUIImpl extends HotSwapUI { for (DebuggerSession session : modifiedClasses.keySet()) { session.setModifiedClassesScanRequired(true); } + callbackWrapper.hotSwapFinished(true, 0, 0, sessions); return; } final Set toReload = new HashSet<>(dialog.getSessionsToReload()); @@ -181,6 +200,7 @@ public class HotSwapUIImpl extends HotSwapUI { for (DebuggerSession session : modifiedClasses.keySet()) { session.setModifiedClassesScanRequired(true); } + callbackWrapper.hotSwapFinished(true, 0, 0, sessions); return; } } @@ -192,6 +212,17 @@ public class HotSwapUIImpl extends HotSwapUI { //noinspection ConstantConditions progress.setSessionForActions(ContainerUtil.getFirstItem(modifiedClasses.keySet())); } + progress.addProgressListener(new HotSwapProgressImpl.HotSwapProgressListener() { + @Override + public void onCancel() { + notifyStatusListener(callbackWrapper, progress, sessions, true); + } + + @Override + public void onFinish() { + notifyStatusListener(callbackWrapper, progress, sessions, false); + } + }); application.executeOnPooledThread(() -> reloadModifiedClasses(modifiedClasses, progress)); } }, ModalityState.NON_MODAL); @@ -212,7 +243,8 @@ public class HotSwapUIImpl extends HotSwapUI { return result.get(); } - private static void reloadModifiedClasses(final Map> modifiedClasses, final HotSwapProgressImpl progress) { + private static void reloadModifiedClasses(final Map> modifiedClasses, + final HotSwapProgressImpl progress) { UsageTrigger.trigger("debugger.reload.classes"); ProgressManager.getInstance().runProcess(() -> { HotSwapManager.reloadModifiedClasses(modifiedClasses, progress); @@ -221,14 +253,25 @@ public class HotSwapUIImpl extends HotSwapUI { } @Override - public void reloadChangedClasses(final DebuggerSession session, boolean compileBeforeHotswap) { + public void reloadChangedClasses(@NotNull DebuggerSession session, boolean compileBeforeHotswap) { + reloadChangedClasses(session, null, compileBeforeHotswap); + } + + @Override + public void reloadChangedClasses(@NotNull DebuggerSession session, @Nullable HotSwapStatusListener callback) { + reloadChangedClasses(session, callback, false); + } + + private void reloadChangedClasses(@NotNull DebuggerSession session, + @Nullable HotSwapStatusListener callback, + boolean compileBeforeHotswap) { dontAskHotswapAfterThisCompilation(); if (compileBeforeHotswap) { CompilerManager.getInstance(session.getProject()).make(null); } else { if (session.isAttached()) { - hotSwapSessions(Collections.singletonList(session), null); + hotSwapSessions(Collections.singletonList(session), null, callback); } } } @@ -278,7 +321,7 @@ public class HotSwapUIImpl extends HotSwapUI { List sessions = getHotSwappableDebugSessions(); if (!sessions.isEmpty()) { - hotSwapSessions(sessions, generated); + hotSwapSessions(sessions, generated, null); } } myPerformHotswapAfterThisCompilation = true; @@ -295,4 +338,14 @@ public class HotSwapUIImpl extends HotSwapUI { .filter(HotSwapUIImpl::canHotSwap) .collect(Collectors.toCollection(SmartList::new)); } + + private static void notifyStatusListener(HotSwapStatusListener listener, + HotSwapProgressImpl progress, + List sessions, + boolean aborted) { + listener.hotSwapFinished(aborted, + progress.getMessages(MessageCategory.ERROR).size(), + progress.getMessages(MessageCategory.WARNING).size(), + sessions); + } } From 38ebc696f8276bd68bd04c6e35af00198fc517d4 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Tue, 13 Feb 2018 18:21:35 +0100 Subject: [PATCH 13/67] IDEA-172018 "Print stacktrace" breakpoint option: fix for AppCode/CLion --- .../intellij/xdebugger/impl/XDebuggerUtilImpl.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index 00495185a9fa..4166bac32441 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.xdebugger.impl; import com.intellij.execution.ui.ConsoleView; @@ -52,6 +50,7 @@ import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil; import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; import com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointFileGroupingRule; import com.intellij.xdebugger.impl.evaluate.quick.common.ValueLookupManager; +import com.intellij.xdebugger.impl.frame.XStackFrameContainerEx; import com.intellij.xdebugger.impl.settings.XDebuggerSettingManagerImpl; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; @@ -541,7 +540,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { public void logStack(@NotNull XSuspendContext suspendContext, @NotNull XDebugSession session) { XExecutionStack activeExecutionStack = suspendContext.getActiveExecutionStack(); if (activeExecutionStack != null) { - activeExecutionStack.computeStackFrames(0, new XExecutionStack.XStackFrameContainer() { + activeExecutionStack.computeStackFrames(0, new XStackFrameContainerEx() { List myFrames = new ArrayList<>(); @Override @@ -552,6 +551,11 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { } } + @Override + public void addStackFrames(@NotNull List stackFrames, @Nullable XStackFrame toSelect, boolean last) { + addStackFrames(stackFrames, last); + } + @Override public void errorOccurred(@NotNull String errorMessage) { print(errorMessage); From e04dc4153a140d4fa49430c1fe58895333544fc1 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 13 Feb 2018 20:22:52 +0300 Subject: [PATCH 14/67] extract and use getStringAttributeValue(PsiAnnotationMemberValue) --- .../intellij/codeInsight/AnnotationUtil.java | 16 ++++-- .../lang/psi/impl/GrAnnotationUtil.java | 57 ++++++------------- .../plugins/groovy/lang/psi/util/PsiUtil.java | 35 +++++------- 3 files changed, 42 insertions(+), 66 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index e59cbd18f79c..0414a666eb63 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInsight; import com.intellij.openapi.project.Project; @@ -480,9 +478,9 @@ public class AnnotationUtil { @Nullable public static String getStringAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findAttributeValue(attributeName); - Object constValue = JavaPsiFacade.getInstance(anno.getProject()).getConstantEvaluationHelper().computeConstantExpression(attrValue); - return constValue instanceof String ? (String)constValue : null; + return attrValue == null ? null : getStringAttributeValue(attrValue); } + @Nullable public static Boolean getBooleanAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findAttributeValue(attributeName); @@ -500,7 +498,13 @@ public class AnnotationUtil { @Nullable public static String getDeclaredStringAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findDeclaredAttributeValue(attributeName); - Object constValue = JavaPsiFacade.getInstance(anno.getProject()).getConstantEvaluationHelper().computeConstantExpression(attrValue); + return attrValue == null ? null : getStringAttributeValue(attrValue); + } + + @Nullable + public static String getStringAttributeValue(@NotNull PsiAnnotationMemberValue attrValue) { + PsiConstantEvaluationHelper evaluationHelper = JavaPsiFacade.getInstance(attrValue.getProject()).getConstantEvaluationHelper(); + Object constValue = evaluationHelper.computeConstantExpression(attrValue); return constValue instanceof String ? (String)constValue : null; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java index f38f64ab4f1c..85d7784465c4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java @@ -1,23 +1,7 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; @@ -27,23 +11,19 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import java.util.Collections; import java.util.List; +import static com.intellij.codeInsight.AnnotationUtil.getStringAttributeValue; +import static com.intellij.openapi.util.text.StringUtil.nullize; +import static com.intellij.util.containers.ContainerUtil.emptyList; +import static com.intellij.util.containers.ContainerUtil.mapNotNull; + /** * @author Max Medvedev */ public class GrAnnotationUtil { - @Nullable - public static String inferStringAttribute(@NotNull PsiAnnotation annotation, @NotNull String attributeName) { - final PsiAnnotationMemberValue targetValue = annotation.findAttributeValue(attributeName); - return getString(targetValue); - } @Nullable - public static String getString(@Nullable PsiAnnotationMemberValue targetValue) { - if (targetValue instanceof PsiLiteral) { - final Object value = ((PsiLiteral)targetValue).getValue(); - if (value instanceof String) return (String)value; - } - return null; + public static String inferStringAttribute(@NotNull PsiAnnotation annotation, @NotNull String attributeName) { + return getStringAttributeValue(annotation, attributeName); } @Nullable @@ -131,11 +111,12 @@ public class GrAnnotationUtil { return (PsiElement)owner; } + @NotNull public static List getClassArrayValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean declared) { PsiAnnotationMemberValue value = declared ? annotation.findDeclaredAttributeValue(attributeName) : annotation.findAttributeValue(attributeName); if (value instanceof PsiArrayInitializerMemberValue) { - return ContainerUtil.mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), GrAnnotationUtil::getPsiClass); + return mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), GrAnnotationUtil::getPsiClass); } else if (value instanceof PsiReference) { PsiClass psiClass = getPsiClass(value); @@ -145,21 +126,17 @@ public class GrAnnotationUtil { return Collections.emptyList(); } + @NotNull public static List getStringArrayValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean declared) { - PsiAnnotationMemberValue value = - declared ? annotation.findDeclaredAttributeValue(attributeName) : annotation.findAttributeValue(attributeName); + PsiAnnotationMemberValue value = declared ? annotation.findDeclaredAttributeValue(attributeName) + : annotation.findAttributeValue(attributeName); if (value instanceof PsiArrayInitializerMemberValue) { - return ContainerUtil.mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), memberValue -> { - String string = getString(memberValue); - return StringUtil.isEmpty(string) ? null : string; - }); + PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers(); + return mapNotNull(initializers, it -> nullize(getStringAttributeValue(it), true)); } else { - String string = getString(value); - if (!StringUtil.isEmpty(string)) { - return Collections.singletonList(string); - } + String string = value == null ? null : nullize(getStringAttributeValue(value), true); + return string == null ? emptyList() : Collections.singletonList(string); } - return Collections.emptyList(); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index e4ce2ca70087..bafc9229eeb3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -1,14 +1,14 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.util; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.light.JavaIdentifier; @@ -1128,26 +1128,21 @@ public class PsiUtil { return (GrCall)eMethodCall; } - public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, String defaultValue) { - PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName); - if (value instanceof GrExpression) { - Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value); - if (o instanceof String) { - return (String)o; - } - } - return defaultValue; + @NotNull + public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, + @NotNull String attributeName, + @NotNull String defaultValue) { + return StringUtil.notNullize(AnnotationUtil.getStringAttributeValue(annotation, attributeName), defaultValue); } - public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, boolean defaultValue) { - PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName); - if (value instanceof GrExpression) { - Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value); - if (o instanceof Boolean) { - return (Boolean)o; - } + public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean defaultValue) { + Boolean value = AnnotationUtil.getBooleanAttributeValue(annotation, attributeName); + if (value == null) { + return defaultValue; + } + else { + return value; } - return defaultValue; } public static boolean isExpressionUsed(PsiElement expr) { From 4dde46ab10b4c191a623688569ace5a6c829c065 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Tue, 13 Feb 2018 20:36:55 +0300 Subject: [PATCH 15/67] cleanup --- .../codeInsight/daemon/impl/HintRenderer.kt | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HintRenderer.kt b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HintRenderer.kt index 77d489ac84db..3945e414e20c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HintRenderer.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/HintRenderer.kt @@ -72,20 +72,13 @@ open class HintRenderer(var text: String?) : EditorCustomElementRenderer { val xEnd = r.x + r.width val y = r.y + ascent val font = editor.getColorsScheme().getFont(EditorFontType.PLAIN) - if (effectType == EffectType.LINE_UNDERSCORE) { - EffectPainter.LINE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) - } - else if (effectType == EffectType.BOLD_LINE_UNDERSCORE) { - EffectPainter.BOLD_LINE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) - } - else if (effectType == EffectType.STRIKEOUT) { - EffectPainter.STRIKE_THROUGH.paint(g2d, xStart, y, xEnd - xStart, editor.charHeight, font) - } - else if (effectType == EffectType.WAVE_UNDERSCORE) { - EffectPainter.WAVE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) - } - else if (effectType == EffectType.BOLD_DOTTED_LINE) { - EffectPainter.BOLD_DOTTED_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) + @Suppress("NON_EXHAUSTIVE_WHEN") + when (effectType) { + EffectType.LINE_UNDERSCORE -> EffectPainter.LINE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) + EffectType.BOLD_LINE_UNDERSCORE -> EffectPainter.BOLD_LINE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) + EffectType.STRIKEOUT -> EffectPainter.STRIKE_THROUGH.paint(g2d, xStart, y, xEnd - xStart, editor.charHeight, font) + EffectType.WAVE_UNDERSCORE -> EffectPainter.WAVE_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) + EffectType.BOLD_DOTTED_LINE -> EffectPainter.BOLD_DOTTED_UNDERSCORE.paint(g2d, xStart, y, xEnd - xStart, descent, font) } } } @@ -147,6 +140,6 @@ open class HintRenderer(var text: String?) : EditorCustomElementRenderer { companion object { private val HINT_FONT_METRICS = Key.create("ParameterHintFontMetrics") - private val BACKGROUND_ALPHA = 0.55f + private const val BACKGROUND_ALPHA = 0.55f } } From 497d6daa7a36354399c59b8a46306a23f94f615f Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Tue, 13 Feb 2018 19:23:32 +0300 Subject: [PATCH 16/67] Fix hanging test and exception when stopping Remote Debug Server (PY-27154) --- .../python/debugger/PyDebugProcess.java | 8 ++++++- .../python/debugger/PyRemoteDebugProcess.java | 21 ++++++++++++++----- python/testData/debug/test_remote.py | 2 +- .../env/python/debug/PyBaseDebuggerTask.java | 6 ++++-- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index b8af92234876..4c98c773f466 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -306,12 +306,18 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr if (myProcessHandler != null) { myProcessHandler.destroyProcess(); } - LOG.error(e); + if (logConnectionException(e)) { + LOG.error(e); + } } } }); } + protected boolean logConnectionException(final Exception e) { + return true; + } + @Override public void init() { getSession().rebuildViews(); diff --git a/python/src/com/jetbrains/python/debugger/PyRemoteDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyRemoteDebugProcess.java index 23d4245fe81d..bed289715152 100644 --- a/python/src/com/jetbrains/python/debugger/PyRemoteDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyRemoteDebugProcess.java @@ -3,11 +3,10 @@ package com.jetbrains.python.debugger; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ui.UIUtil; import com.intellij.xdebugger.XDebugSession; -import com.jetbrains.python.debugger.PyDebugProcess; -import com.jetbrains.python.debugger.PyRemoteDebugProcessAware; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,6 +18,7 @@ import java.net.ServerSocket; public class PyRemoteDebugProcess extends PyDebugProcess { private final int myLocalPort; private final String mySettraceCall; + private boolean isStopCalled = false; public PyRemoteDebugProcess(@NotNull XDebugSession session, @NotNull final ServerSocket serverSocket, @@ -56,11 +56,22 @@ public class PyRemoteDebugProcess extends PyDebugProcess { return "Waiting for connection"; } + @Override + protected boolean logConnectionException(Exception e) { + return !(isStopCalled && e.getMessage().contains("closed")); + } + @Override protected void detachDebuggedProcess() { waitForNextConnection(); // in case of remote debug we should wait for the next connection } + @Override + public void stop() { + super.stop(); + isStopCalled = true; + } + @Override protected void beforeConnect() { printToConsole(getCurrentStateMessage() + "\n", ConsoleViewContentType.SYSTEM_OUTPUT); @@ -79,8 +90,8 @@ public class PyRemoteDebugProcess extends PyDebugProcess { } if (!isWaitingForConnection()) { setWaitingForConnection(true); - - UIUtil.invokeLaterIfNeeded(() -> waitForConnection(getCurrentStateMessage(), getConnectionTitle())); + ApplicationManager.getApplication().invokeLater(() -> waitForConnection(getCurrentStateMessage(), getConnectionTitle()), + ModalityState.defaultModalityState()); } } diff --git a/python/testData/debug/test_remote.py b/python/testData/debug/test_remote.py index 8bccbeb44c4f..d2a241213070 100644 --- a/python/testData/debug/test_remote.py +++ b/python/testData/debug/test_remote.py @@ -9,7 +9,7 @@ if __name__ == '__main__': x = 0 - from pydev import pydevd + import pydevd pydevd.settrace('localhost', port=port, stdoutToServer=True, stderrToServer=True) x = 1 diff --git a/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java b/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java index 23e9ecbcdb65..075d299abf72 100644 --- a/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java +++ b/python/testSrc/com/jetbrains/env/python/debug/PyBaseDebuggerTask.java @@ -17,6 +17,8 @@ package com.jetbrains.env.python.debug; import com.google.common.collect.Sets; import com.intellij.execution.ExecutionResult; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.project.Project; @@ -241,8 +243,8 @@ public abstract class PyBaseDebuggerTask extends PyExecutionFixtureTestTask { } protected void clearAllBreakpoints() { - - UIUtil.invokeAndWaitIfNeeded((Runnable)() -> XDebuggerTestUtil.removeAllBreakpoints(getProject())); + ApplicationManager.getApplication() + .invokeLater(() -> XDebuggerTestUtil.removeAllBreakpoints(getProject()), ModalityState.defaultModalityState()); } /** From b12d83e9dfdd0ffe4d3a3dc53ad53ddfe9c054d7 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 13 Feb 2018 21:19:33 +0300 Subject: [PATCH 17/67] Revert "extract and use getStringAttributeValue(PsiAnnotationMemberValue)" This reverts commit e04dc41 --- .../intellij/codeInsight/AnnotationUtil.java | 16 ++---- .../lang/psi/impl/GrAnnotationUtil.java | 57 +++++++++++++------ .../plugins/groovy/lang/psi/util/PsiUtil.java | 35 +++++++----- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index 0414a666eb63..e59cbd18f79c 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -1,4 +1,6 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package com.intellij.codeInsight; import com.intellij.openapi.project.Project; @@ -478,9 +480,9 @@ public class AnnotationUtil { @Nullable public static String getStringAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findAttributeValue(attributeName); - return attrValue == null ? null : getStringAttributeValue(attrValue); + Object constValue = JavaPsiFacade.getInstance(anno.getProject()).getConstantEvaluationHelper().computeConstantExpression(attrValue); + return constValue instanceof String ? (String)constValue : null; } - @Nullable public static Boolean getBooleanAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findAttributeValue(attributeName); @@ -498,13 +500,7 @@ public class AnnotationUtil { @Nullable public static String getDeclaredStringAttributeValue(@NotNull PsiAnnotation anno, @Nullable final String attributeName) { PsiAnnotationMemberValue attrValue = anno.findDeclaredAttributeValue(attributeName); - return attrValue == null ? null : getStringAttributeValue(attrValue); - } - - @Nullable - public static String getStringAttributeValue(@NotNull PsiAnnotationMemberValue attrValue) { - PsiConstantEvaluationHelper evaluationHelper = JavaPsiFacade.getInstance(attrValue.getProject()).getConstantEvaluationHelper(); - Object constValue = evaluationHelper.computeConstantExpression(attrValue); + Object constValue = JavaPsiFacade.getInstance(anno.getProject()).getConstantEvaluationHelper().computeConstantExpression(attrValue); return constValue instanceof String ? (String)constValue : null; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java index 85d7784465c4..f38f64ab4f1c 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrAnnotationUtil.java @@ -1,7 +1,23 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; @@ -11,19 +27,23 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import java.util.Collections; import java.util.List; -import static com.intellij.codeInsight.AnnotationUtil.getStringAttributeValue; -import static com.intellij.openapi.util.text.StringUtil.nullize; -import static com.intellij.util.containers.ContainerUtil.emptyList; -import static com.intellij.util.containers.ContainerUtil.mapNotNull; - /** * @author Max Medvedev */ public class GrAnnotationUtil { - @Nullable public static String inferStringAttribute(@NotNull PsiAnnotation annotation, @NotNull String attributeName) { - return getStringAttributeValue(annotation, attributeName); + final PsiAnnotationMemberValue targetValue = annotation.findAttributeValue(attributeName); + return getString(targetValue); + } + + @Nullable + public static String getString(@Nullable PsiAnnotationMemberValue targetValue) { + if (targetValue instanceof PsiLiteral) { + final Object value = ((PsiLiteral)targetValue).getValue(); + if (value instanceof String) return (String)value; + } + return null; } @Nullable @@ -111,12 +131,11 @@ public class GrAnnotationUtil { return (PsiElement)owner; } - @NotNull public static List getClassArrayValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean declared) { PsiAnnotationMemberValue value = declared ? annotation.findDeclaredAttributeValue(attributeName) : annotation.findAttributeValue(attributeName); if (value instanceof PsiArrayInitializerMemberValue) { - return mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), GrAnnotationUtil::getPsiClass); + return ContainerUtil.mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), GrAnnotationUtil::getPsiClass); } else if (value instanceof PsiReference) { PsiClass psiClass = getPsiClass(value); @@ -126,17 +145,21 @@ public class GrAnnotationUtil { return Collections.emptyList(); } - @NotNull public static List getStringArrayValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean declared) { - PsiAnnotationMemberValue value = declared ? annotation.findDeclaredAttributeValue(attributeName) - : annotation.findAttributeValue(attributeName); + PsiAnnotationMemberValue value = + declared ? annotation.findDeclaredAttributeValue(attributeName) : annotation.findAttributeValue(attributeName); if (value instanceof PsiArrayInitializerMemberValue) { - PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers(); - return mapNotNull(initializers, it -> nullize(getStringAttributeValue(it), true)); + return ContainerUtil.mapNotNull(((PsiArrayInitializerMemberValue)value).getInitializers(), memberValue -> { + String string = getString(memberValue); + return StringUtil.isEmpty(string) ? null : string; + }); } else { - String string = value == null ? null : nullize(getStringAttributeValue(value), true); - return string == null ? emptyList() : Collections.singletonList(string); + String string = getString(value); + if (!StringUtil.isEmpty(string)) { + return Collections.singletonList(string); + } } + return Collections.emptyList(); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index bafc9229eeb3..e4ce2ca70087 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -1,14 +1,14 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +/* + * Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ package org.jetbrains.plugins.groovy.lang.psi.util; -import com.intellij.codeInsight.AnnotationUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.light.JavaIdentifier; @@ -1128,21 +1128,26 @@ public class PsiUtil { return (GrCall)eMethodCall; } - @NotNull - public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, - @NotNull String attributeName, - @NotNull String defaultValue) { - return StringUtil.notNullize(AnnotationUtil.getStringAttributeValue(annotation, attributeName), defaultValue); + public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, String defaultValue) { + PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName); + if (value instanceof GrExpression) { + Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value); + if (o instanceof String) { + return (String)o; + } + } + return defaultValue; } - public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, @NotNull String attributeName, boolean defaultValue) { - Boolean value = AnnotationUtil.getBooleanAttributeValue(annotation, attributeName); - if (value == null) { - return defaultValue; - } - else { - return value; + public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, boolean defaultValue) { + PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName); + if (value instanceof GrExpression) { + Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value); + if (o instanceof Boolean) { + return (Boolean)o; + } } + return defaultValue; } public static boolean isExpressionUsed(PsiElement expr) { From 88dbf34634f3fede7433ee379d8975411271f126 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Feb 2018 19:05:30 +0100 Subject: [PATCH 18/67] jetCheck: an easier way to debug the minimal counterexample failure --- jetCheck/src/org/jetbrains/jetCheck/Iteration.java | 4 +++- .../src/org/jetbrains/jetCheck/PropertyFalsified.java | 9 +++++++++ jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/jetCheck/src/org/jetbrains/jetCheck/Iteration.java b/jetCheck/src/org/jetbrains/jetCheck/Iteration.java index 5f025524abfe..fb03491b1d13 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/Iteration.java +++ b/jetCheck/src/org/jetbrains/jetCheck/Iteration.java @@ -71,7 +71,9 @@ class Iteration { String rechecking = failureReason != null && StatusNotifier.printStackTrace(failureReason).contains("ImperativeCommand.checkScenario") ? "ImperativeCommand.checkScenario(" + iterationSeed + "L, " + sizeHint + ", ...))\n" : "PropertyChecker.forAll(...).rechecking(" + iterationSeed + "L, " + sizeHint + ").shouldHold(...)\n"; - return "To reproduce the last iteration, run " + rechecking + "Global seed: " + session.globalSeed + "L"; + return "To reproduce the last iteration, run " + rechecking + + "To debug the minimal failing example, catch this exception and invoke 'replayMinimalExample' on it.\n" + + "Global seed: " + session.globalSeed + "L"; } String printSeeds() { diff --git a/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java b/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java index b76fa019050c..a1789a4ebfda 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java +++ b/jetCheck/src/org/jetbrains/jetCheck/PropertyFalsified.java @@ -125,4 +125,13 @@ public class PropertyFalsified extends RuntimeException { public DataStructure getData() { return failure.getMinimalCounterexample().createReplayData(); } + + /** + * Re-invoke the generator and the property check on the minimal counter-example found after testing and shrinking. Useful for debugging.

+ * + * The same as {@code getFailure().getMinimalCounterexample().replay()}. + */ + public PropertyFailure.CounterExample replayMinimalExample() { + return failure.getMinimalCounterexample().replay(); + } } diff --git a/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java b/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java index c4e53bada88e..fdbb4f90279f 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/ExceptionTest.java @@ -68,4 +68,13 @@ public class ExceptionTest extends PropertyCheckerTestCase { } } + public void testRecommendReplay() { + PropertyFalsified e = checkFails(forAllStable(integers()), i -> { + throw new AssertionError("fail"); + }); + + assertTrue(e.getMessage().contains("replayMinimalExample")); + assertNotNull(e.replayMinimalExample()); + } + } From 055c1d6e65ac6acf0ee973aeb4efe84fe0c4ea26 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Feb 2018 19:14:07 +0100 Subject: [PATCH 19/67] jetCheck: shrink chars to range lower bound --- jetCheck/src/org/jetbrains/jetCheck/Generator.java | 2 +- jetCheck/src/org/jetbrains/jetCheck/StructureNode.java | 8 +++++++- jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java | 7 ++++++- jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/jetCheck/src/org/jetbrains/jetCheck/Generator.java b/jetCheck/src/org/jetbrains/jetCheck/Generator.java index e76579cd327c..6046d2896294 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/Generator.java +++ b/jetCheck/src/org/jetbrains/jetCheck/Generator.java @@ -176,7 +176,7 @@ public class Generator { /** Generates characters in the given range (both ends inclusive) */ public static Generator charsInRange(char min, char max) { - return integers(min, max).map(i -> (char)i.intValue()).noShrink(); + return integers(min, max).map(i -> (char)i.intValue()); } /** Generates ASCII characters excluding the system ones (lower than 32) */ diff --git a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java b/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java index 0bac624a566a..d1089e2c9d9e 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java +++ b/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java @@ -229,7 +229,13 @@ class IntData extends StructureElement { @Nullable @Override ShrinkStep shrink() { - return value == 0 ? null : tryInt(0, () -> null, this::tryNegation); + if (value == 0) return null; + + int minValue = 0; + if (distribution instanceof BoundedIntDistribution) { + minValue = Math.max(minValue, ((BoundedIntDistribution)distribution).getMin()); + } + return tryInt(minValue, () -> null, this::tryNegation); } private ShrinkStep tryNegation() { diff --git a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java index 4ee859583a8f..f67c35154d81 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java @@ -35,7 +35,7 @@ public class GeneratorTest extends PropertyCheckerTestCase { public void testStringContains() { assertEquals("a", checkGeneratesExample(stringsOf(asciiPrintableChars()), s -> s.contains("a"), - 8)); + 10)); } public void testLetterStringContains() { @@ -173,4 +173,9 @@ public class GeneratorTest extends PropertyCheckerTestCase { assertEquals(log, Collections.singletonList(goldMin)); } + public void testShrinkToRangeStart() { + PropertyFailure failure = checkFalsified(stringsOf(asciiUppercaseChars()), s -> s.length() < 5, 11); + assertEquals("AAAAA", failure.getMinimalCounterexample().getExampleValue()); + } + } diff --git a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java b/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java index 7153086b1d84..d8869fdb4b9e 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java @@ -21,7 +21,7 @@ public class ShrinkTest extends PropertyCheckerTestCase { String s = l.toString(); return !"abcdefghijklmnopqrstuvwxyz()[]#!".chars().allMatch(c -> s.indexOf((char)c) >= 0); }, - 254); + 356); } public void testShrinkingNonEmptyList() { From 1416ea54168cfea68f73c896cdc6ef15c7d3c7b9 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Feb 2018 19:29:21 +0100 Subject: [PATCH 20/67] jetCheck: shrink children starting from the end to likely decrease number of variants in stateful generators --- jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java | 2 +- jetCheck/src/org/jetbrains/jetCheck/StructureNode.java | 9 +++++---- jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java | 6 +++--- jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java | 2 +- .../org/jetbrains/jetCheck/StatefulGeneratorTest.java | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java b/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java index 6af694f74546..662a82a63b92 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java +++ b/jetCheck/src/org/jetbrains/jetCheck/RemoveListRange.java @@ -56,7 +56,7 @@ class RemoveListRange extends ShrinkStep { } int newEnd = start == 1 ? node.children.size() : start; - if (newEnd == lastSuccessfulRemove) return node.shrinkChild(1); + if (newEnd == lastSuccessfulRemove) return node.shrinkChild(node.children.size() - 1); return new RemoveListRange(node, lastSuccessfulRemove, newEnd - 1, 1); } diff --git a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java b/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java index d1089e2c9d9e..3bd6f26e2101 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java +++ b/jetCheck/src/org/jetbrains/jetCheck/StructureNode.java @@ -69,12 +69,13 @@ class StructureNode extends StructureElement { ShrinkStep shrink() { if (shrinkProhibited) return null; - return isList() ? new RemoveListRange(this) : shrinkChild(0); + return isList() ? new RemoveListRange(this) : shrinkChild(children.size() - 1); } @Nullable ShrinkStep shrinkChild(int index) { - for (; index < children.size(); index++) { + int minIndex = isList() ? 1 : 0; + for (; index >= minIndex; index--) { ShrinkStep childShrink = children.get(index).shrink(); if (childShrink != null) return wrapChildShrink(index, childShrink); } @@ -84,7 +85,7 @@ class StructureNode extends StructureElement { @Nullable private ShrinkStep wrapChildShrink(int index, @Nullable ShrinkStep step) { - if (step == null) return shrinkChild(index + 1); + if (step == null) return shrinkChild(index - 1); NodeId oldChild = children.get(index).id; @@ -248,7 +249,7 @@ class IntData extends StructureElement { private ShrinkStep divisionLoop(int value) { if (value == 0) return null; int divided = value / 2; - return tryInt(divided, () -> divisionLoop(divided / 2), null); + return tryInt(divided, () -> divisionLoop(divided), null); } private ShrinkStep tryInt(int value, @NotNull Supplier success, @Nullable Supplier fail) { diff --git a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java index f67c35154d81..00b8469a7469 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/GeneratorTest.java @@ -23,7 +23,7 @@ public class GeneratorTest extends PropertyCheckerTestCase { public void testListSumMod() { checkFalsified(nonEmptyLists(integers()), l -> l.stream().mapToInt(Integer::intValue).sum() % 10 != 0, - 390); + 223); } public void testListContainsDivisible() { @@ -47,7 +47,7 @@ public class GeneratorTest extends PropertyCheckerTestCase { public void testIsSorted() { PropertyFailure> failure = checkFalsified(nonEmptyLists(integers()), l -> l.stream().sorted().collect(Collectors.toList()).equals(l), - 22); + 36); List value = failure.getMinimalCounterexample().getExampleValue(); assertEquals(2, value.size()); assertTrue(value.toString(), value.stream().allMatch(i -> Math.abs(i) < 2)); @@ -60,7 +60,7 @@ public class GeneratorTest extends PropertyCheckerTestCase { public void testSortedDoublesNonDescending() { PropertyFailure> failure = checkFalsified(listsOf(doubles()), l -> isSorted(l.stream().sorted().collect(Collectors.toList())), - 23); + 21); assertEquals(2, failure.getMinimalCounterexample().getExampleValue().size()); } diff --git a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java b/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java index d8869fdb4b9e..445036d8b971 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/ShrinkTest.java @@ -21,7 +21,7 @@ public class ShrinkTest extends PropertyCheckerTestCase { String s = l.toString(); return !"abcdefghijklmnopqrstuvwxyz()[]#!".chars().allMatch(c -> s.indexOf((char)c) >= 0); }, - 356); + 298); } public void testShrinkingNonEmptyList() { diff --git a/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java b/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java index c43dbfcf0f83..49909f326709 100644 --- a/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java +++ b/jetCheck/test/org/jetbrains/jetCheck/StatefulGeneratorTest.java @@ -56,7 +56,7 @@ public class StatefulGeneratorTest extends PropertyCheckerTestCase { }; env.executeCommands(withRecursion(insertStringCmd(sb), replace, deleteStringCmd(sb), checkDoesNotContain(sb, "A"))); - }), Scenario::ensureSuccessful, 56).getMinimalCounterexample().getExampleValue(); + }), Scenario::ensureSuccessful, 55).getMinimalCounterexample().getExampleValue(); assertEquals("commands:\n" + " insert A at 0\n" + From bdf820c4ab76ec9cb0331f5f2bd63534b9974ddb Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Feb 2018 19:41:46 +0100 Subject: [PATCH 21/67] ensure performWhenAllCommitted works for documents for files with ignored names --- .../psi/impl/PsiDocumentManagerBase.java | 5 +++++ .../psi/impl/PsiDocumentManagerImplTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index d8157ec3fa1c..7b52cfe2cb0d 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -823,6 +823,11 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } List files = viewProvider.getAllFiles(); + if (files.isEmpty()) { + handleCommitWithoutPsi(document); + return; + } + boolean commitNecessary = files.stream().noneMatch(file -> PsiToDocumentSynchronizer.isInsideAtomicChange(file) || !(file instanceof PsiFileImpl)); boolean forceCommit = ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class) && diff --git a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java index fb7e72163535..476205da267a 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java @@ -928,4 +928,20 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { PsiElement firstChild = psiFile.getFirstChild(); assertTrue(firstChild instanceof PsiComment); } + + public void testAutoCommitDoesNotGetStuckForDocumentsWithIgnoredFileName() throws IOException { + VirtualFile vFile = getVirtualFile(createTempFile("a.txt~", "text")); + assertNotNull(getPsiManager().findViewProvider(vFile)); + assertNull(getPsiManager().findFile(vFile)); // because it's ignored + + Document document = FileDocumentManager.getInstance().getDocument(vFile); + ApplicationManager.getApplication().runWriteAction(() -> document.setText("// things")); + + boolean[] calledPerformWhenAllCommitted = new boolean[1]; + getPsiDocumentManager().performWhenAllCommitted(() -> calledPerformWhenAllCommitted[0] = true); + waitForCommits(); + + assertTrue(getPsiDocumentManager().isCommitted(document)); + assertTrue(calledPerformWhenAllCommitted[0]); + } } \ No newline at end of file From eac5448e1cb92932a85eecb8e0491b73d0a0b1dd Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 13 Feb 2018 22:34:27 +0300 Subject: [PATCH 22/67] IDEA-186651 diff: shortcut for "Move to Another Changelist" should not affect whole file * do not use same shortcut for "Move to Another Changelist" and "Move Lines to Another Changelist" --- .../src/messages/ActionsBundle.properties | 6 ++--- .../src/idea/VcsActions.xml | 6 ++--- .../lst/SimpleLocalChangeListDiffViewer.java | 22 +++++++++++++++---- .../vcs/ex/MoveChangesLineStatusAction.java | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index c99e2d994900..0a47569e220f 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -1171,9 +1171,9 @@ action.Vcs.ShowDiffAction.text=Show Changes action.Vcs.ShowDiffAction.description=Show changes action.Vcs.RollbackChanges.text=Rollback Changes action.Vcs.RollbackChanges.description=Rollback changes -action.Vcs.MoveChangedLinesToChangelist.text=Move to Another Changelist... -action.Vcs.MoveChangedLinesToChangelist.description=Move selected changes to another changelist -action.Vcs.RollbackChangedLines.text=Rollback +action.Vcs.MoveChangedLinesToChangelist.text=Move Lines to Another Changelist... +action.Vcs.MoveChangedLinesToChangelist.description=Move changes in selected lines to another changelist +action.Vcs.RollbackChangedLines.text=Rollback Lines action.Vcs.RollbackChangedLines.description=Rollback changes in selected lines action.Vcs.EditSourceAction.text=Edit Source action.Vcs.EditSourceAction.description=Edit source diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml index 0e2e1e4af162..3dccc7e1de7b 100644 --- a/platform/platform-resources/src/idea/VcsActions.xml +++ b/platform/platform-resources/src/idea/VcsActions.xml @@ -312,8 +312,7 @@ - + @@ -370,6 +369,8 @@ + + @@ -413,7 +414,6 @@ - diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java index 701ac2d7dbe5..e5606df0a016 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/lst/SimpleLocalChangeListDiffViewer.java @@ -12,6 +12,7 @@ import com.intellij.diff.util.Range; import com.intellij.diff.util.Side; import com.intellij.icons.AllIcons; import com.intellij.idea.ActionsBundle; +import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -36,7 +37,6 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.List; -import static com.intellij.util.ObjectUtils.assertNotNull; import static com.intellij.util.ObjectUtils.notNull; public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer { @@ -53,7 +53,7 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer { myTracker.addListener(new MyTrackerListener(), this); - DiffUtil.registerAction(new MoveSelectedChangesToAnotherChangelistAction(), myPanel); + DiffUtil.registerAction(new MoveSelectedChangesToAnotherChangelistAction(true), myPanel); } @NotNull @@ -68,7 +68,7 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer { protected List createEditorPopupActions() { List group = new ArrayList<>(super.createEditorPopupActions()); - group.add(new MoveSelectedChangesToAnotherChangelistAction()); + group.add(new MoveSelectedChangesToAnotherChangelistAction(false)); return group; } @@ -185,8 +185,20 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer { } private class MoveSelectedChangesToAnotherChangelistAction extends DumbAwareAction { + private final boolean myShortcut; + + public MoveSelectedChangesToAnotherChangelistAction(boolean shortcut) { + myShortcut = shortcut; + copyShortcutFrom(ActionManager.getInstance().getAction("Vcs.MoveChangedLinesToChangelist")); + } + @Override public void update(@NotNull AnActionEvent e) { + if (myShortcut) { + e.getPresentation().setEnabledAndVisible(true); + return; + } + Editor editor = e.getData(CommonDataKeys.EDITOR); Side side = Side.fromValue(getEditors(), editor); if (side == null) { @@ -215,7 +227,9 @@ public class SimpleLocalChangeListDiffViewer extends SimpleDiffViewer { @Override public void actionPerformed(@NotNull AnActionEvent e) { Editor editor = e.getData(CommonDataKeys.EDITOR); - Side side = assertNotNull(Side.fromValue(getEditors(), editor)); + Side side = Side.fromValue(getEditors(), editor); + if (editor == null || side == null) return; + List selectedChanges = getSelectedChanges(side); if (selectedChanges.isEmpty()) return; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java index e5643d574a6a..b4c18c6f123e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/MoveChangesLineStatusAction.java @@ -97,7 +97,7 @@ public class MoveChangesLineStatusAction extends LineStatusActionBase { ChangeListChooser chooser = new ChangeListChooser(project, suggestedLists, defaultSelection, - ActionsBundle.message("action.ChangesView.Move.text"), + ActionsBundle.message("action.Vcs.MoveChangedLinesToChangelist.text"), null); chooser.show(); From 484c9e29b960e685a25aba2403ef159a2f978d2f Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Feb 2018 20:45:44 +0100 Subject: [PATCH 23/67] mad testing: don't shrink offsets to speed up minimization --- jetCheck/src/org/jetbrains/jetCheck/Generator.java | 4 +++- .../src/org/jetbrains/jetCheck/ImperativeCommand.java | 5 ++++- .../testFramework/propertyBased/ActionOnRange.java | 11 +++++++++++ .../testFramework/propertyBased/DeleteRange.java | 5 ++--- .../propertyBased/InsertLineComment.java | 2 +- .../testFramework/propertyBased/InsertString.java | 2 +- .../testFramework/propertyBased/InvokeCompletion.java | 3 +-- .../testFramework/propertyBased/InvokeIntention.java | 5 ++--- .../testFramework/propertyBased/MadTestingUtil.java | 2 -- 9 files changed, 25 insertions(+), 14 deletions(-) diff --git a/jetCheck/src/org/jetbrains/jetCheck/Generator.java b/jetCheck/src/org/jetbrains/jetCheck/Generator.java index 6046d2896294..6d6e1eefd6c9 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/Generator.java +++ b/jetCheck/src/org/jetbrains/jetCheck/Generator.java @@ -73,7 +73,9 @@ public class Generator { /** * Turns off automatic minimization for the data produced by this generator (and its components, if any). - * This can be useful to speed up minimization by not wasting time on shrinking objects where it makes no sense. + * This can be useful to speed up minimization by not wasting time on shrinking objects where it makes no sense. + * It's especially useful when using stateful generators (e.g. {@link ImperativeCommand}), because + * shrinkable values there can lead to doubling of the shrinking time. */ public Generator noShrink() { return from(data -> data.generateNonShrinkable(this)); diff --git a/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java b/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java index 07a7472a0c86..25073df67947 100644 --- a/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java +++ b/jetCheck/src/org/jetbrains/jetCheck/ImperativeCommand.java @@ -82,7 +82,10 @@ public interface ImperativeCommand { * The message is a Java format string, so you can use it to include the generated value, e.g. * {@code String s = generateValue(stringsOf(asciiLetters(), "Generated %s")}.

* If you don't want to generate message, or would like to show the generated value in a custom way, pass {@code null}. - * You can use {@link #logMessage} later to still leave a trace of this value generation in the log. + * You can use {@link #logMessage} later to still leave a trace of this value generation in the log.

+ * + * Consider making generators non-shrinkable (by invoking {@link Generator#noShrink()}) where possible + * because it can speed up overall failing scenario minimization significantly. */ T generateValue(@NotNull Generator generator, @Nullable String logMessage); diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/ActionOnRange.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/ActionOnRange.java index 6c5010d31e6c..69089eca3f3a 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/ActionOnRange.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/ActionOnRange.java @@ -29,6 +29,7 @@ import com.intellij.psi.SmartPsiFileRange; import com.intellij.psi.impl.DebugUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jetCheck.Generator; /** * @author peter @@ -98,4 +99,14 @@ abstract class ActionOnRange implements MadTestingAction { } return myFinalRange; } + + @SuppressWarnings("SameParameterValue") + protected int generatePsiOffset(@NotNull Environment env, @Nullable String logMessage) { + return env.generateValue(Generator.integers(0, getFile().getTextLength()).noShrink(), logMessage); + } + + protected int generateDocOffset(@NotNull Environment env, @Nullable String logMessage) { + return env.generateValue(Generator.integers(0, getDocument().getTextLength()).noShrink(), logMessage); + } + } diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java index 5e3f9296958b..c1861e2ddb21 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/DeleteRange.java @@ -36,9 +36,8 @@ public class DeleteRange extends ActionOnRange { public void performCommand(@NotNull Environment env) { PsiFile psiFile = getFile(); - int fileLength = psiFile.getTextLength(); - int startOffset = env.generateValue(Generator.integers(0, fileLength), null); - int endOffset = Math.min(fileLength, startOffset + env.generateValue(Generator.integers(IntDistribution.geometric(10)), null)); + int startOffset = generatePsiOffset(env, null); + int endOffset = Math.min(psiFile.getTextLength(), startOffset + env.generateValue(Generator.integers(IntDistribution.geometric(10)).noShrink(), null)); PsiElement start = psiFile.findElementAt(startOffset); PsiElement end = psiFile.findElementAt(endOffset); if (start == null || end == null) return; diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertLineComment.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertLineComment.java index 8de374acc294..f534241bd2e9 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertLineComment.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertLineComment.java @@ -25,7 +25,7 @@ public class InsertLineComment extends ActionOnRange { public void performCommand(@NotNull Environment env) { PsiDocumentManager.getInstance(getProject()).commitDocument(getDocument()); - int randomOffset = env.generateValue(Generator.integers(0, getFile().getTextLength()), null); + int randomOffset = generatePsiOffset(env, null); PsiElement leaf = getFile().findElementAt(randomOffset); TextRange leafRange = leaf != null ? leaf.getTextRange() : null; int insertOffset = leafRange != null ? leafRange.getEndOffset() : 0; diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertString.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertString.java index 1b4d8f3a94b5..36e137cf1393 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertString.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InsertString.java @@ -30,7 +30,7 @@ public class InsertString extends ActionOnRange { @Override public void performCommand(@NotNull Environment env) { - int offset = env.generateValue(Generator.integers(0, getDocument().getTextLength()), null); + int offset = generateDocOffset(env, null); String toInsert = env.generateValue(Generator.stringsOf(Generator.asciiPrintableChars()), "Insert '%s' at " + offset + " in " + getPath()); WriteCommandAction.runWriteCommandAction(getProject(), () -> getDocument().insertString(offset, toInsert)); } diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeCompletion.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeCompletion.java index b0bc49eff3d7..859e42f249f6 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeCompletion.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeCompletion.java @@ -82,8 +82,7 @@ public class InvokeCompletion extends ActionOnRange { @Override public void performCommand(@NotNull Environment env) { - int offset = env.generateValue(Generator.integers(0, getDocument().getTextLength()), - "Invoke basic completion at offset %s (" + getPath() + ")"); + int offset = generateDocOffset(env, "Invoke basic completion at offset %s (" + getPath() + ")"); String selectionCharacters = myPolicy.getPossibleSelectionCharacters(); char c = selectionCharacters.charAt(env.generateValue(Generator.integers(0, selectionCharacters.length() - 1), null)); performActionAt(offset, c, items -> env.generateValue(Generator.sampledFrom(items), null), env::logMessage); diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeIntention.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeIntention.java index b6574dfb13bc..4f52c0b541fe 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeIntention.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/InvokeIntention.java @@ -74,8 +74,7 @@ public class InvokeIntention extends ActionOnRange { @Override public void performCommand(@NotNull Environment env) { - int offset = env.generateValue(Generator.integers(0, getDocument().getTextLength()), - "Go to offset %s and run daemon (" + getPath() + ")"); + int offset = generateDocOffset(env, "Go to offset %s and run daemon (" + getPath() + ")"); doInvokeIntention(offset, actions -> { if (actions.isEmpty()) { @@ -83,7 +82,7 @@ public class InvokeIntention extends ActionOnRange { return null; } - IntentionAction result = env.generateValue(Generator.sampledFrom(actions), null); + IntentionAction result = env.generateValue(Generator.sampledFrom(actions).noShrink(), null); env.logMessage("Invoke intention '" + result.getText() + "'"); return result; }); diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/MadTestingUtil.java b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/MadTestingUtil.java index bdee0c122595..5ff29a54bfb0 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/MadTestingUtil.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/propertyBased/MadTestingUtil.java @@ -41,7 +41,6 @@ import com.intellij.testFramework.RunAll; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.fixtures.CodeInsightTestFixture; import com.intellij.util.ThrowableRunnable; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.JBIterable; import com.intellij.util.containers.TreeTraversal; import com.intellij.util.ui.UIUtil; @@ -236,7 +235,6 @@ public class MadTestingUtil { return () -> env -> new RunAll() .append(() -> { File ioFile = env.generateValue(randomFiles, "Working with %s"); - System.out.println(ioFile); VirtualFile vFile = copyFileToProject(ioFile, fixture, rootPath); PsiFile psiFile = fixture.getPsiManager().findFile(vFile); if (psiFile instanceof PsiBinaryFile || psiFile instanceof PsiPlainTextFile) { From ae5ff6ccc8afba46a882f7db98a893c9d2471a1e Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 12 Feb 2018 23:47:02 +0300 Subject: [PATCH 24/67] [vcs-log] reset log state when initialization is cancelled or fails If a git executable is improperly configured, log initialization does not work. After correct executable is configured, it needs to be done again. The initialization can be done when one of the tabs is opened, when one of roots is refreshed or when user presses Refresh button. IDEA-186463 --- .../com/intellij/vcs/log/data/VcsLogData.java | 47 ++++++++++++++++--- .../vcs/log/impl/PostponableLogRefresher.java | 2 + 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java index ec22ccfe7431..56deb18e4dc9 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java @@ -92,7 +92,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { @NotNull private final VcsLogIndex myIndex; @NotNull private final Object myLock = new Object(); - private boolean myInitialized = false; + @NotNull private State myState = State.CREATED; @Nullable private SingleTaskController.SingleTask myInitialization = null; public VcsLogData(@NotNull Project project, @@ -164,8 +164,8 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { public void initialize() { synchronized (myLock) { - if (!myInitialized) { - myInitialized = true; + if (myState.equals(State.CREATED)) { + myState = State.INITIALIZED; StopWatch stopWatch = StopWatch.start("initialize"); Task.Backgroundable backgroundable = new Task.Backgroundable(myProject, "Loading History...", false) { @Override @@ -179,9 +179,38 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { } @Override - public void onFinished() { + public void onCancel() { synchronized (myLock) { - myInitialization = null; + // Here be dragons: + // VcsLogProgressManager can cancel us when it's getting disposed, + // and we can also get cancelled by invalid git executable. + // Since we do not know what's up, we just restore the state + // and it is entirely possible to start another initialization after that. + // Eventually, everything gets cancelled for good in VcsLogData.dispose. + // But still. + if (myState.equals(State.INITIALIZED)) { + myState = State.CREATED; + myInitialization = null; + } + } + } + + @Override + public void onThrowable(@NotNull Throwable error) { + synchronized (myLock) { + if (myState.equals(State.INITIALIZED)) { + myState = State.CREATED; + myInitialization = null; + } + } + } + + @Override + public void onSuccess() { + synchronized (myLock) { + if (myState.equals(State.INITIALIZED)) { + myInitialization = null; + } } } }; @@ -291,6 +320,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { * @param roots roots to refresh */ public void refreshSoftly(@NotNull Set roots) { + initialize(); myRefresher.refresh(roots); } @@ -299,6 +329,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { * This refresh can be optimized, i. e. it can query VCS just for the part of the log. */ public void refresh(@NotNull Collection roots) { + initialize(); myRefresher.refresh(roots); } @@ -318,7 +349,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { synchronized (myLock) { initialization = myInitialization; myInitialization = null; - myInitialized = true; + myState = State.DISPOSED; } if (initialization != null) { @@ -357,4 +388,8 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { public VcsLogIndex getIndex() { return myIndex; } + + private enum State { + CREATED, INITIALIZED, DISPOSED + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java index 957658282e45..cde3c874043e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java @@ -74,6 +74,8 @@ public class PostponableLogRefresher implements VcsLogRefresher { } public void filtererActivated(@NotNull VisiblePackRefresher refresher, boolean firstTime) { + myLogData.initialize(); + if (!myRootsToRefresh.isEmpty()) { refreshPostponedRoots(); } From ef117fc2f9053841f298bde1ff0c1bc60eab1357 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 13 Feb 2018 17:01:39 +0300 Subject: [PATCH 25/67] [vcs-log] rename filtererActivated -> refresherActivated --- .../com/intellij/vcs/log/impl/PostponableLogRefresher.java | 4 ++-- .../impl/src/com/intellij/vcs/log/impl/VcsLogTabsWatcher.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java index cde3c874043e..eb63c46ed88b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/PostponableLogRefresher.java @@ -48,7 +48,7 @@ public class PostponableLogRefresher implements VcsLogRefresher { @NotNull public Disposable addLogWindow(@NotNull VcsLogWindow window) { myLogWindows.add(window); - filtererActivated(window.getRefresher(), true); + refresherActivated(window.getRefresher(), true); return () -> myLogWindows.remove(window); } @@ -73,7 +73,7 @@ public class PostponableLogRefresher implements VcsLogRefresher { return false; } - public void filtererActivated(@NotNull VisiblePackRefresher refresher, boolean firstTime) { + public void refresherActivated(@NotNull VisiblePackRefresher refresher, boolean firstTime) { myLogData.initialize(); if (!myRootsToRefresh.isEmpty()) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogTabsWatcher.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogTabsWatcher.java index b233acf188bf..69bc923ecbdd 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogTabsWatcher.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogTabsWatcher.java @@ -146,7 +146,7 @@ public class VcsLogTabsWatcher implements Disposable { VcsLogWindow logWindow = ContainerUtil.find(myRefresher.getLogWindows(), window -> window instanceof VcsLogTab && ((VcsLogTab)window).myTabName.equals(tabName)); if (logWindow != null) { - myRefresher.filtererActivated(logWindow.getRefresher(), false); + myRefresher.refresherActivated(logWindow.getRefresher(), false); } } From 89575ada6750be7fcb9ec1aa5ac51222d763560e Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Wed, 14 Feb 2018 01:39:08 +0300 Subject: [PATCH 26/67] Adjust gaps between buttons (Find/Replace in path) --- .../src/com/intellij/find/impl/FindPopupPanel.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindPopupPanel.java b/platform/lang-impl/src/com/intellij/find/impl/FindPopupPanel.java index 7db8b2b4787e..0178174a885d 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindPopupPanel.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindPopupPanel.java @@ -712,9 +712,10 @@ public class FindPopupPanel extends JBPanel implements FindUI { bottomPanel.add(Box.createHorizontalGlue(), "growx, pushx"); myOKHintLabel = new JBLabel(""); myOKHintLabel.setEnabled(false); - bottomPanel.add(myOKHintLabel, "gapright " + JBUI.scale(8)); - bottomPanel.add(myOKButton, "gapright " + JBUI.scale(12)); - bottomPanel.add(myReplaceAllButton, "gapright " + JBUI.scale(12)); + Insets insets = myOKButton.getInsets(); + bottomPanel.add(myOKHintLabel, "gapright " + Math.max(0, (JBUI.scale(8) - insets.left))); + bottomPanel.add(myOKButton, "gapright " + Math.max(0, (JBUI.scale(12) - insets.left - insets.right))); + bottomPanel.add(myReplaceAllButton, "gapright " + Math.max(0, (JBUI.scale(12) - insets.left - insets.right))); bottomPanel.add(myReplaceSelectedButton); myCodePreviewComponent = myUsagePreviewPanel.createComponent(); From 5b2f2af6973bffe1f1dedfc3c16d4763db7c6f24 Mon Sep 17 00:00:00 2001 From: Vitaly Provodin Date: Wed, 14 Feb 2018 05:25:10 +0300 Subject: [PATCH 27/67] Updating versions of project dependencies: jdkBuild->u152b1153.1 Vitaly Provodin --- build/dependencies/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/dependencies/gradle.properties b/build/dependencies/gradle.properties index eae2587cbec6..4dc0c7cf84f1 100644 --- a/build/dependencies/gradle.properties +++ b/build/dependencies/gradle.properties @@ -1,5 +1,5 @@ # The file might be automatically updated. Comments and empty lines will be removed. kotlinPluginBuild=1.2.30-eap-16-IJ2018.1-1:ideadev jetSignBuild=42.30 -jdkBuild=u152b1136.12 +jdkBuild=u152b1153.1 gradleApiVersion=4.4 From 85222dd3c1ef8cb8579abd6b87199925bca21920 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 14 Feb 2018 13:26:24 +0800 Subject: [PATCH 28/67] Make "ChangesModuleGroupingPolicy" open for api compatibility --- .../openapi/vcs/changes/ui/ChangesModuleGroupingPolicy.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesModuleGroupingPolicy.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesModuleGroupingPolicy.kt index ab15ce16e170..d2af567d2ddb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesModuleGroupingPolicy.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesModuleGroupingPolicy.kt @@ -16,7 +16,7 @@ import javax.swing.tree.DefaultTreeModel private const val PROJECT_ROOT_TAG = "" -class ChangesModuleGroupingPolicy(val myProject: Project, val myModel: DefaultTreeModel) : ChangesGroupingPolicy { +open class ChangesModuleGroupingPolicy(val myProject: Project, val myModel: DefaultTreeModel) : ChangesGroupingPolicy { private val myIndex = ProjectFileIndex.getInstance(myProject) override fun getParentNodeFor(nodePath: StaticFilePath, subtreeRoot: ChangesBrowserNode<*>): ChangesBrowserNode<*>? { From 5c8092c1d683d2d42afd5086671b0fe4b88c3902 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 14 Feb 2018 11:33:45 +0300 Subject: [PATCH 29/67] cleanup language extensions after area change --- .../src/com/intellij/lang/LanguageExtension.java | 10 ++++++++++ .../intellij/openapi/util/KeyedExtensionCollector.java | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/lang/LanguageExtension.java b/platform/core-api/src/com/intellij/lang/LanguageExtension.java index a1c70265b47e..e67ecc616a5f 100644 --- a/platform/core-api/src/com/intellij/lang/LanguageExtension.java +++ b/platform/core-api/src/com/intellij/lang/LanguageExtension.java @@ -49,6 +49,16 @@ public class LanguageExtension extends KeyedExtensionCollector { return key.getID(); } + @Override + protected void dropCaches() { + super.dropCaches(); + if (IN_LANGUAGE_CACHE != null) { + for (Language language : Language.getRegisteredLanguages()) { + language.putUserData(IN_LANGUAGE_CACHE, null); + } + } + } + public T forLanguage(@NotNull Language l) { T cached = l.getUserData(IN_LANGUAGE_CACHE); if (cached != null) return cached; diff --git a/platform/core-api/src/com/intellij/openapi/util/KeyedExtensionCollector.java b/platform/core-api/src/com/intellij/openapi/util/KeyedExtensionCollector.java index f5c7a5b5efe5..5951a3c51aa1 100644 --- a/platform/core-api/src/com/intellij/openapi/util/KeyedExtensionCollector.java +++ b/platform/core-api/src/com/intellij/openapi/util/KeyedExtensionCollector.java @@ -81,10 +81,14 @@ public class KeyedExtensionCollector { @Override public void areaReplaced(@NotNull final ExtensionsArea area) { - myCache.clear(); + dropCaches(); } }; + protected void dropCaches() { + myCache.clear(); + } + public KeyedExtensionCollector(@NonNls @NotNull String epName) { myEpName = epName; lock = "lock for KeyedExtensionCollector " + epName; @@ -94,7 +98,7 @@ public class KeyedExtensionCollector { if (extensionPoint.getName().equals(epName)) { //noinspection unchecked extensionPoint.addExtensionPointListener(myListener); - myCache.clear(); + dropCaches(); } } From e0e734045a20368543df08d5fd1d1c879ccb5543 Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Wed, 14 Feb 2018 11:59:26 +0300 Subject: [PATCH 30/67] cleanup overriding hashCode is rather useless here --- platform/util/src/com/intellij/util/LazyInitializer.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/util/src/com/intellij/util/LazyInitializer.java b/platform/util/src/com/intellij/util/LazyInitializer.java index 36a320e6a5c8..e27776e630ea 100644 --- a/platform/util/src/com/intellij/util/LazyInitializer.java +++ b/platform/util/src/com/intellij/util/LazyInitializer.java @@ -95,9 +95,4 @@ public class LazyInitializer { public String toString() { return value != null ? value.toString() : "null"; } - - @Override - public int hashCode() { - return value != null ? value.hashCode() : super.hashCode(); - } } From 50d77c65c6bccf61986df717fb0b9521393246be Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Wed, 14 Feb 2018 12:16:37 +0300 Subject: [PATCH 31/67] IDEA-162950 Allow to open source code for a class in alternative JDK when debugging - require reboot --- platform/util/resources/misc/registry.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index a83fe26465e8..55b595f1a0d1 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -392,6 +392,7 @@ debugger.enable.overhead.monitor=true debugger.tree.states.depth=100 index.run.configuration.jre=false +index.run.configuration.jre.restartRequired=true index.run.configuration.jre.description=Index jre specified in run configuration for goto navigation etc. analyze.exceptions.on.the.fly=false From 968f7baf5b5cabe0b39ad0397738737ef3af8e1c Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 14 Feb 2018 10:49:41 +0100 Subject: [PATCH 32/67] CallToSimpleGetterInClassInspectionBase: simpler check first --- .../CallToSimpleGetterInClassInspectionBase.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CallToSimpleGetterInClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CallToSimpleGetterInClassInspectionBase.java index d8bc3908d56c..d44a8be2188d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CallToSimpleGetterInClassInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CallToSimpleGetterInClassInspectionBase.java @@ -18,6 +18,7 @@ package com.siyeh.ig.performance; import com.intellij.psi.*; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PropertyUtilBase; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; @@ -60,6 +61,13 @@ public class CallToSimpleGetterInClassInspectionBase extends BaseInspection { @Override public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { super.visitMethodCallExpression(call); + + String referenceName = call.getMethodExpression().getReferenceName(); + if (referenceName == null || + PropertyUtilBase.getMethodNameGetterFlavour(referenceName) == PropertyUtilBase.GetterFlavour.NOT_A_GETTER) { + return; + } + final PsiClass containingClass = ClassUtils.getContainingClass(call); if (containingClass == null) { return; From 4d4873299adbb931b23a247cb6dbbda0d530b498 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 14 Feb 2018 10:53:14 +0100 Subject: [PATCH 33/67] SuspiciousMethodCallUtil: calculate containing method lazily after checking that name is interesting improves performance on some deep call chains --- .../codeInspection/miscGenerics/SuspiciousMethodCallUtil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java index 675d9d994059..fd7450047d5c 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/SuspiciousMethodCallUtil.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection.miscGenerics; import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.openapi.util.NullableLazyValue; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -167,7 +168,7 @@ public class SuspiciousMethodCallUtil { PsiElement element = resolveResult.getElement(); if (!(element instanceof PsiMethod)) return null; PsiMethod calleeMethod = (PsiMethod)element; - PsiMethod contextMethod = PsiTreeUtil.getParentOfType(methodExpression, PsiMethod.class); + NullableLazyValue lazyContextMethod = NullableLazyValue.createValue(() -> PsiTreeUtil.getParentOfType(methodExpression, PsiMethod.class)); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (patternMethods) { @@ -182,6 +183,7 @@ public class SuspiciousMethodCallUtil { int index = indices.get(i); //we are in collections method implementation + PsiMethod contextMethod = lazyContextMethod.getValue(); if (contextMethod != null && isInheritorOrSelf(contextMethod, patternMethod)) return null; final PsiClass calleeClass = calleeMethod.getContainingClass(); From 6a981ec0a9e6300f7494038f7bbd17b1d9ae8704 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 14 Feb 2018 11:03:13 +0100 Subject: [PATCH 34/67] performance tests: allow +10% more time on the last iteration --- .../src/com/intellij/testFramework/PerformanceTestInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/PerformanceTestInfo.java b/platform/testFramework/src/com/intellij/testFramework/PerformanceTestInfo.java index 4ed815ab2e31..31d8caafffaa 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PerformanceTestInfo.java +++ b/platform/testFramework/src/com/intellij/testFramework/PerformanceTestInfo.java @@ -122,7 +122,7 @@ public class PerformanceTestInfo { int expectedOnMyMachine = getExpectedTimeOnThisMachine(); // Allow 10% more in case of test machine is busy. - double acceptableChangeFactor = attempts == 1 ? 1.1 : 1.0; + double acceptableChangeFactor = attempts == 0 ? 1.1 : 1.0; int percentage = (int)(100.0 * (duration - expectedOnMyMachine) / expectedOnMyMachine); String colorCode = duration < expectedOnMyMachine ? "32;1m" : // green duration < expectedOnMyMachine * acceptableChangeFactor ? "33;1m" : // yellow From af0f7b007bb5b353b582ccc2e251b94ae25c01aa Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 13 Feb 2018 18:04:09 +0100 Subject: [PATCH 35/67] IG: use PsiExpressionList.isEmpty() some more --- .../bugs/ImplicitArrayToStringInspection.java | 16 ++++--------- .../ig/bugs/ObjectToStringInspection.java | 6 ++--- .../ig/bugs/ParameterClassCheckVisitor.java | 9 ++----- .../ig/cloneable/UseOfCloneInspection.java | 23 ++---------------- ...ewExceptionWithoutArgumentsInspection.java | 12 ++++------ .../PropertyValueSetToItselfInspection.java | 20 ++-------------- .../ForCanBeForeachInspectionBase.java | 24 +++---------------- .../WhileCanBeForeachInspectionBase.java | 20 ++-------------- ...atingObjectToGetClassObjectInspection.java | 7 +----- ...fferMustHaveInitialCapacityInspection.java | 8 ++----- .../siyeh/ig/threading/ThreadingUtils.java | 6 ++--- .../migration/ForCanBeForeachInspection.java | 10 +++----- .../SizeReplaceableByIsEmptyInspection.java | 4 +--- 13 files changed, 30 insertions(+), 135 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ImplicitArrayToStringInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ImplicitArrayToStringInspection.java index 7e0df264053e..dda54ad08cb1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ImplicitArrayToStringInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ImplicitArrayToStringInspection.java @@ -201,21 +201,13 @@ public class ImplicitArrayToStringInspection extends BaseInspection { registerError(expression, expression, Boolean.FALSE); } - private static boolean isExplicitArrayToStringCall( - PsiMethodCallExpression expression) { - final PsiReferenceExpression methodExpression = - expression.getMethodExpression(); + private static boolean isExplicitArrayToStringCall(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); final String methodName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.TO_STRING.equals(methodName)) { + if (!HardcodedMethodConstants.TO_STRING.equals(methodName) || !expression.getArgumentList().isEmpty()) { return false; } - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { - return false; - } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier == null) { return false; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ObjectToStringInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ObjectToStringInspection.java index f740e24c27a5..1e7068a80aee 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ObjectToStringInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ObjectToStringInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,9 +103,7 @@ public class ObjectToStringInspection extends BaseInspection { final PsiReferenceExpression methodExpression = expression.getMethodExpression(); @NonNls final String name = methodExpression.getReferenceName(); if (HardcodedMethodConstants.TO_STRING.equals(name)) { - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + if (!expression.getArgumentList().isEmpty()) { return; } final PsiExpression qualifier = methodExpression.getQualifierExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ParameterClassCheckVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ParameterClassCheckVisitor.java index 986d6daee600..16ed75ade3da 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ParameterClassCheckVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ParameterClassCheckVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,12 +79,7 @@ class ParameterClassCheckVisitor extends JavaRecursiveElementWalkingVisitor { private boolean isGetClassCall(PsiMethodCallExpression methodCallExpression) { final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final String methodName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.GET_CLASS.equals(methodName)) { - return false; - } - final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + if (!HardcodedMethodConstants.GET_CLASS.equals(methodName) || !methodCallExpression.getArgumentList().isEmpty()) { return false; } final PsiMethod method = methodCallExpression.resolveMethod(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/UseOfCloneInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/UseOfCloneInspection.java index 544975a4d099..ecc0c4c4fbaa 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/UseOfCloneInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/UseOfCloneInspection.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.cloneable; import com.intellij.psi.*; @@ -63,12 +49,7 @@ public class UseOfCloneInspection extends BaseInspection { public void visitMethodCallExpression(PsiMethodCallExpression expression) { final PsiReferenceExpression methodExpression = expression.getMethodExpression(); final String referenceName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.CLONE.equals(referenceName)) { - return; - } - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + if (!HardcodedMethodConstants.CLONE.equals(referenceName) || !expression.getArgumentList().isEmpty()) { return; } final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java index e48499935057..c7a998e339e3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 Bas Leijdekkers + * Copyright 2011-2018 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,17 +47,13 @@ public class NewExceptionWithoutArgumentsInspection extends BaseInspection { return new NewExceptionWithoutArgumentsVisitor(); } - private class NewExceptionWithoutArgumentsVisitor extends BaseInspectionVisitor { + private static class NewExceptionWithoutArgumentsVisitor extends BaseInspectionVisitor { @Override public void visitNewExpression(PsiNewExpression expression) { super.visitNewExpression(expression); final PsiExpressionList argumentList = expression.getArgumentList(); - if (argumentList == null) { - return; - } - final PsiExpression[] expressions = argumentList.getExpressions(); - if (expressions.length != 0) { + if (argumentList == null || !argumentList.isEmpty()) { return; } final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); @@ -77,7 +73,7 @@ public class NewExceptionWithoutArgumentsInspection extends BaseInspection { } } - private boolean hasAccessibleConstructorWithParameters(PsiClass aClass, PsiElement context) { + private static boolean hasAccessibleConstructorWithParameters(PsiClass aClass, PsiElement context) { final PsiMethod[] constructors = aClass.getConstructors(); for (PsiMethod constructor : constructors) { final PsiParameterList parameterList = constructor.getParameterList(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java index 2407842e954c..f8b499b94837 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.javabeans; import com.intellij.psi.*; @@ -63,9 +49,7 @@ public class PropertyValueSetToItselfInspection extends BaseInspection { return; } final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)argument; - final PsiExpressionList argumentList2 = methodCallExpression.getArgumentList(); - final PsiExpression[] arguments2 = argumentList2.getExpressions(); - if (arguments2.length != 0) { + if (!methodCallExpression.getArgumentList().isEmpty()) { return; } final PsiReferenceExpression methodExpression1 = expression.getMethodExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java index 48c994ccd518..588e8e8a3dec 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/ForCanBeForeachInspectionBase.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.migration; import com.intellij.psi.*; @@ -213,9 +199,7 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { if (!HardcodedMethodConstants.ITERATOR.equals(initialCallName) && !"listIterator".equals(initialCallName)) { return false; } - final PsiExpressionList argumentList = initialCall.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + if (!initialCall.getArgumentList().isEmpty()) { return false; } final PsiExpression qualifier = ExpressionUtils.getQualifierOrThis(initialMethodExpression); @@ -281,9 +265,7 @@ public class ForCanBeForeachInspectionBase extends BaseInspection { return false; } final PsiMethodCallExpression call = (PsiMethodCallExpression)condition; - final PsiExpressionList argumentList = call.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + if (!call.getArgumentList().isEmpty()) { return false; } final PsiReferenceExpression methodExpression = call.getMethodExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java index 3a7da3fc6adb..e841d85d748f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/WhileCanBeForeachInspectionBase.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.migration; import com.intellij.psi.*; @@ -111,9 +97,7 @@ public class WhileCanBeForeachInspectionBase extends BaseInspection { return false; } final PsiMethodCallExpression initialCall = (PsiMethodCallExpression)initialValue; - final PsiExpressionList argumentList = initialCall.getArgumentList(); - final PsiExpression[] argument = argumentList.getExpressions(); - if (argument.length != 0) { + if (!initialCall.getArgumentList().isEmpty()) { return false; } final PsiReferenceExpression initialMethodExpression = initialCall.getMethodExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InstantiatingObjectToGetClassObjectInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InstantiatingObjectToGetClassObjectInspection.java index f7d034ecaa91..6f3ebe3e6212 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InstantiatingObjectToGetClassObjectInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InstantiatingObjectToGetClassObjectInspection.java @@ -120,12 +120,7 @@ public class InstantiatingObjectToGetClassObjectInspection expression.getMethodExpression(); @NonNls final String methodName = methodExpression.getReferenceName(); - if (!"getClass".equals(methodName)) { - return; - } - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] args = argumentList.getExpressions(); - if (args.length != 0) { + if (!"getClass".equals(methodName) || !expression.getArgumentList().isEmpty()) { return; } final PsiExpression qualifier = diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java index ebc8c448f1fd..c30978d785f2 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,11 +65,7 @@ public class StringBufferMustHaveInitialCapacityInspection return; } final PsiExpressionList argumentList = expression.getArgumentList(); - if (argumentList == null) { - return; - } - final PsiExpression[] args = argumentList.getExpressions(); - if (args.length != 0) { + if (argumentList == null || !argumentList.isEmpty()) { return; } registerNewExpressionError(expression); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ThreadingUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ThreadingUtils.java index e4df1f001605..681a38335d6d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ThreadingUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/ThreadingUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,9 +80,7 @@ class ThreadingUtils { if (!"signal".equals(methodName) && !"signalAll".equals(methodName)) { return false; } - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] args = argumentList.getExpressions(); - if (args.length != 0) { + if (!expression.getArgumentList().isEmpty()) { return false; } final PsiMethod method = expression.resolveMethod(); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java index f39ad14714ac..230007ba6718 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2017 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -749,12 +749,8 @@ public class ForCanBeForeachInspection extends ForCanBeForeachInspectionBase { if (!(element instanceof PsiMethodCallExpression)) { return false; } - final PsiMethodCallExpression callExpression = - (PsiMethodCallExpression)element; - final PsiExpressionList argumentList = - callExpression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 0) { + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)element; + if (!callExpression.getArgumentList().isEmpty()) { return false; } final PsiReferenceExpression reference = diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java index 49e6d49c508e..7d35fe68211d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SizeReplaceableByIsEmptyInspection.java @@ -150,9 +150,7 @@ public class SizeReplaceableByIsEmptyInspection extends BaseInspection { if (!HardcodedMethodConstants.SIZE.equals(referenceName) && !HardcodedMethodConstants.LENGTH.equals(referenceName)) { return; } - final PsiExpressionList argumentList = callExpression.getArgumentList(); - final PsiExpression[] expressions = argumentList.getExpressions(); - if (expressions.length != 0) { + if (!callExpression.getArgumentList().isEmpty()) { return; } final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); From 0c6d98f3a2a936bfeb721c6ae95b88876e3dcdb1 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 14 Feb 2018 11:12:33 +0100 Subject: [PATCH 36/67] IG: fix r/w detection in nested array access expressions (IDEA-186461) --- .../MismatchedArrayReadWriteInspection.java | 8 ++++++-- .../MismatchedArrayReadWrite.java | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java index 396c5e5663ab..71b75d0f785e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2017 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -174,6 +174,9 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { } return true; } + else if (expression instanceof PsiLiteralExpression) { + return false; + } return true; } @@ -235,7 +238,8 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { if (parent instanceof PsiArrayAccessExpression) { PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression)parent; parent = getParent(parent); - while (parent instanceof PsiArrayAccessExpression) { + while (parent instanceof PsiArrayAccessExpression && + ((PsiArrayAccessExpression)parent).getArrayExpression() == arrayAccessExpression) { arrayAccessExpression = (PsiArrayAccessExpression)parent; parent = getParent(parent); } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java index 167fdd57dbb9..5226c1bc66e0 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java @@ -263,4 +263,23 @@ class ParentRecorder { public void treeEdge(int e, int g) { parents[e] = g; } +} +class Example { + private final int[] reducedToFull; + Example() { + reducedToFull = new int[]{1, 2, 4}; + reducedToFull[2] = 3; + } + void method(String[] fullOrders, String[] reducedOrders) { + for (int j = 0; j < reducedOrders.length; j++) { + fullOrders[reducedToFull[j]] = reducedOrders[j]; + } + } +} +class Example2 { + private final int[] is; + Example2() { + is = new int[] {36, 42, 12}; + is[1] = 27; + } } \ No newline at end of file From 4b895f88804921e87cd4ba7739e937d9f92edc80 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Wed, 14 Feb 2018 12:21:10 +0300 Subject: [PATCH 37/67] Uast-groovy: `GrULiteral.evaluate` implementation and equals for `GrUNamedExpression` --- .../groovy/lang/psi/uast/GroovyUastPlugin.kt | 10 +++++++-- .../plugins/groovy/uast/GroovyUastApiTest.kt | 22 ++++++++++++++++--- .../uast/SimpleGroovyRenderingLogTest.kt | 3 +++ .../testData/Annotations.groovy | 12 ++++++++++ .../testData/Annotations.log.txt | 20 +++++++++++++++++ .../testData/Annotations.render.txt | 12 ++++++++++ 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 plugins/groovy/groovy-uast-tests/testData/Annotations.groovy create mode 100644 plugins/groovy/groovy-uast-tests/testData/Annotations.log.txt create mode 100644 plugins/groovy/groovy-uast-tests/testData/Annotations.render.txt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/uast/GroovyUastPlugin.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/uast/GroovyUastPlugin.kt index 664b83e59938..611e93c8b061 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/uast/GroovyUastPlugin.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/uast/GroovyUastPlugin.kt @@ -67,8 +67,8 @@ class GroovyUastPlugin : UastLanguagePlugin { } class GrULiteral(val grElement: GrLiteral, val parentProvider: () -> UElement?) : ULiteralExpression, JvmDeclarationUElement { - override val value: Any? - get() = grElement.value + override val value: Any? get() = grElement.value + override fun evaluate(): Any? = value override val uastParent by lazy(parentProvider) override val psi: PsiElement? = grElement override val annotations: List = emptyList() //not implemented @@ -85,6 +85,12 @@ class GrUNamedExpression(val grElement: GrAnnotationNameValuePair, val parentPro override val psi = grElement override val annotations: List = emptyList() //not implemented + override fun equals(other: Any?): Boolean { + if (other !is GrUNamedExpression) return false + return grElement == other.grElement + } + + override fun hashCode(): Int = grElement.hashCode() } class GrUAnnotation(val grElement: GrAnnotation, diff --git a/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/GroovyUastApiTest.kt b/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/GroovyUastApiTest.kt index 580ea3376035..5282be94a93a 100644 --- a/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/GroovyUastApiTest.kt +++ b/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/GroovyUastApiTest.kt @@ -4,10 +4,9 @@ package org.jetbrains.plugins.groovy.uast import junit.framework.TestCase -import org.jetbrains.uast.UAnnotation -import org.jetbrains.uast.UAnnotationEx -import org.jetbrains.uast.UFile +import org.jetbrains.uast.* import org.jetbrains.uast.test.env.findElementByText +import org.jetbrains.uast.test.env.findElementByTextFromPsi import org.junit.Test class GroovyUastApiTest : AbstractGroovyUastTest() { @@ -34,4 +33,21 @@ class GroovyUastApiTest : AbstractGroovyUastTest() { } } + @Test + fun testStringLiteral() { + doTest("Annotations.groovy") { name, file -> + file.findElementByTextFromPsi("\"abc\"").let { literal -> + TestCase.assertTrue(literal.isStringLiteral()) + TestCase.assertEquals("abc", literal.value) + TestCase.assertEquals("abc", literal.getValueIfStringLiteral()) + } + file.findElementByTextFromPsi("123").let { literal -> + TestCase.assertFalse(literal.isStringLiteral()) + TestCase.assertEquals(123, literal.value) + TestCase.assertEquals(null, literal.getValueIfStringLiteral()) + } + + } + } + } \ No newline at end of file diff --git a/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/SimpleGroovyRenderingLogTest.kt b/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/SimpleGroovyRenderingLogTest.kt index 873c8dd72183..c1b6718e903c 100644 --- a/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/SimpleGroovyRenderingLogTest.kt +++ b/plugins/groovy/groovy-uast-tests/test/org/jetbrains/plugins/groovy/uast/SimpleGroovyRenderingLogTest.kt @@ -14,4 +14,7 @@ class SimpleGroovyRenderingLogTest : AbstractGroovyRenderLogTest() { @Test fun testClassWithInners() = doTest("ClassWithInners.groovy") + @Test + fun testAnnotations() = doTest("Annotations.groovy") + } \ No newline at end of file diff --git a/plugins/groovy/groovy-uast-tests/testData/Annotations.groovy b/plugins/groovy/groovy-uast-tests/testData/Annotations.groovy new file mode 100644 index 000000000000..d12b5582402b --- /dev/null +++ b/plugins/groovy/groovy-uast-tests/testData/Annotations.groovy @@ -0,0 +1,12 @@ +@interface MyAnnotation { + String value() + String name() default "" + int count() default 0 + Class cls() default null +} + +@MyAnnotation("abc") +class A1{} + +@MyAnnotation(value = "ghi", name = "myName", count = 123, cls = String.class) +class A3{} \ No newline at end of file diff --git a/plugins/groovy/groovy-uast-tests/testData/Annotations.log.txt b/plugins/groovy/groovy-uast-tests/testData/Annotations.log.txt new file mode 100644 index 000000000000..f6968c324589 --- /dev/null +++ b/plugins/groovy/groovy-uast-tests/testData/Annotations.log.txt @@ -0,0 +1,20 @@ +UFile (package = ) + UClass (name = MyAnnotation) + UMethod (name = value) + UMethod (name = name) + UMethod (name = count) + UMethod (name = cls) + UClass (name = A1) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = null) + ULiteralExpression (value = "abc") + UClass (name = A3) + UAnnotation (fqName = MyAnnotation) + UNamedExpression (name = value) + ULiteralExpression (value = "ghi") + UNamedExpression (name = name) + ULiteralExpression (value = "myName") + UNamedExpression (name = count) + ULiteralExpression (value = 123) + UNamedExpression (name = cls) + UReferenceExpression diff --git a/plugins/groovy/groovy-uast-tests/testData/Annotations.render.txt b/plugins/groovy/groovy-uast-tests/testData/Annotations.render.txt new file mode 100644 index 000000000000..85a3430eb1da --- /dev/null +++ b/plugins/groovy/groovy-uast-tests/testData/Annotations.render.txt @@ -0,0 +1,12 @@ +public abstract annotation MyAnnotation { + public abstract fun value() : java.lang.String = UastEmptyExpression + public abstract fun name() : java.lang.String = UastEmptyExpression + public abstract fun count() : int = UastEmptyExpression + public abstract fun cls() : java.lang.Class = UastEmptyExpression +} + +public class A1 { +} + +public class A3 { +} From 7f56eb1fbbc550e79f4555ec5985df0ac0fe62d9 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Wed, 14 Feb 2018 12:23:53 +0300 Subject: [PATCH 38/67] TestDataReferenceContributor: fixes for making Groovy work (IDEA-140461) (IDEA-CR-29257) --- .../src/testAssistant/TestDataReferenceContributor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/devkit/src/testAssistant/TestDataReferenceContributor.java b/plugins/devkit/src/testAssistant/TestDataReferenceContributor.java index 4034a6ee70f3..927f196b2521 100644 --- a/plugins/devkit/src/testAssistant/TestDataReferenceContributor.java +++ b/plugins/devkit/src/testAssistant/TestDataReferenceContributor.java @@ -70,7 +70,8 @@ public class TestDataReferenceContributor extends PsiReferenceContributor { //ideally `literalExpression.getValue()` should be the right value for `stringValue`, but something is wrong with Kotlin String stringValue; if (literalExpression.getSourcePsi() == host) { - stringValue = range.substring(host.getText()); + stringValue = UastLiteralUtils.getValueIfStringLiteral(literalExpression); + if (stringValue == null) return PsiReference.EMPTY_ARRAY; } else { StringBuilder chars = new StringBuilder(); @@ -87,7 +88,7 @@ public class TestDataReferenceContributor extends PsiReferenceContributor { } private static class TestDataReferenceSet extends FileReferenceSet { - public TestDataReferenceSet(String str, + public TestDataReferenceSet(@NotNull String str, @NotNull PsiElement element, int startInElement, @Nullable PsiReferenceProvider provider, From 8ac2d9e9d04c20f1858984abffa1d09ca8738dd7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 13 Feb 2018 16:21:55 +0100 Subject: [PATCH 39/67] ability to serialize property that returns immutable list --- .../xml/XmlSerializerOldMapAnnotationTest.kt | 8 +- .../util/xmlb/AbstractCollectionBinding.java | 114 +++++------------- .../com/intellij/util/xmlb/ArrayBinding.java | 34 +++--- .../intellij/util/xmlb/CollectionBinding.java | 49 ++++---- .../com/intellij/util/xmlb/MapBinding.java | 2 +- .../tasks/generic/GenericRepository.java | 9 +- 6 files changed, 81 insertions(+), 135 deletions(-) diff --git a/platform/configuration-store-impl/testSrc/xml/XmlSerializerOldMapAnnotationTest.kt b/platform/configuration-store-impl/testSrc/xml/XmlSerializerOldMapAnnotationTest.kt index 2011a07daeff..35094b85a8bf 100644 --- a/platform/configuration-store-impl/testSrc/xml/XmlSerializerOldMapAnnotationTest.kt +++ b/platform/configuration-store-impl/testSrc/xml/XmlSerializerOldMapAnnotationTest.kt @@ -96,17 +96,17 @@ internal class XmlSerializerOldMapAnnotationTest { @Tag("bean") class BeanWithMapWithSetValue { @MapAnnotation(entryTagName = "entry-tag", keyAttributeName = "key-attr", surroundWithTag = false) - var myValues = LinkedHashMap>() + var values = LinkedHashMap>() } val bean = BeanWithMapWithSetValue() - bean.myValues.put("a", LinkedHashSet(Arrays.asList("first1", "second1"))) - bean.myValues.put("b", LinkedHashSet(Arrays.asList("first2", "second2"))) + bean.values.put("a", linkedSetOf("first1", "second1")) + bean.values.put("b", linkedSetOf("first2", "second2")) testSerializer(""" -