From a34a010cd6251c927e6b6cbb282ce92c959f78aa Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 4 Feb 2019 11:55:03 +0300 Subject: [PATCH 001/138] IDEA-111333 Provide Sublime Text keymap fix a conflict with CLion action --- .../platform-resources/src/keymaps/Sublime Text (Mac OS X).xml | 1 + platform/platform-resources/src/keymaps/Sublime Text.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml b/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml index 00206672262f..d423e9ce4dd8 100644 --- a/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml +++ b/platform/platform-resources/src/keymaps/Sublime Text (Mac OS X).xml @@ -56,6 +56,7 @@ + diff --git a/platform/platform-resources/src/keymaps/Sublime Text.xml b/platform/platform-resources/src/keymaps/Sublime Text.xml index 69b7f7027eea..8f6452fe06fb 100644 --- a/platform/platform-resources/src/keymaps/Sublime Text.xml +++ b/platform/platform-resources/src/keymaps/Sublime Text.xml @@ -62,6 +62,7 @@ + From 13bb32bbb6accbfaf8ac4a28c61df20fcfab3631 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 4 Feb 2019 11:55:18 +0300 Subject: [PATCH 002/138] IDEA-111333 Provide Sublime Text keymap tests fixes --- .../extensions/src/com/intellij/keymap/KeymapsTestCase.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java index 74962d37f166..c577be148754 100644 --- a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java +++ b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java @@ -391,6 +391,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { "ActivateStructureToolWindow", "ActivateTODOToolWindow", "ActivateWebToolWindow", "ActivatePaletteToolWindow", "ActivateTerminalToolWindow", "IDEtalk.SearchUserHistory", "IDEtalk.SearchUserHistory", "IDEtalk.Rename", + "CIDR.Lang.Cpp.GenerateDefinitions", "" ); From 5f7ee5437dd70c0a12f1cedca6c16efbab9bc791 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 4 Feb 2019 12:03:32 +0300 Subject: [PATCH 003/138] IDEA-CR-42557 build scripts: support common build with jre 8 and 11 bundled --- .../intellij/build/impl/LinuxDistributionBuilder.groovy | 8 +++----- .../intellij/build/impl/MacDistributionBuilder.groovy | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy index cbbedb5c10ef..4e65f7462891 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/LinuxDistributionBuilder.groovy @@ -60,11 +60,11 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder { void buildArtifacts(String osSpecificDistPath) { buildContext.executeStep("Build Linux .tar.gz", BuildOptions.LINUX_ARTIFACTS_STEP) { if (customizer.buildTarGzWithoutBundledJre) { - buildTarGz(null, osSpecificDistPath) + buildTarGz(null, osSpecificDistPath, "-no-jdk") } def jreDirectoryPath = buildContext.bundledJreManager.extractLinuxJre() if (jreDirectoryPath != null) { - buildTarGz(jreDirectoryPath, osSpecificDistPath) + buildTarGz(jreDirectoryPath, osSpecificDistPath, buildContext.bundledJreManager.jreSuffix()) buildSnapPackage(jreDirectoryPath, osSpecificDistPath) } else { @@ -134,10 +134,8 @@ class LinuxDistributionBuilder extends OsSpecificDistributionBuilder { buildContext.ant.fixcrlf(file: "$unixDistPath/bin/Install-Linux-tar.txt", eol: "unix") } - private void buildTarGz(String jreDirectoryPath, String unixDistPath, String secondJreSuffix = null) { + private void buildTarGz(String jreDirectoryPath, String unixDistPath, String suffix) { def tarRoot = customizer.getRootDirectoryName(buildContext.applicationInfo, buildContext.buildNumber) - def suffix = secondJreSuffix - if (suffix == null) suffix = jreDirectoryPath != null ? buildContext.bundledJreManager.jreSuffix() : "-no-jdk" def tarPath = "$buildContext.paths.artifacts/${buildContext.productProperties.getBaseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${suffix}.tar" def extraBins = customizer.extraExecutables def paths = [buildContext.paths.distAll, unixDistPath] diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy index 26f2ef77f725..39fa5536d193 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/MacDistributionBuilder.groovy @@ -272,12 +272,12 @@ class MacDistributionBuilder extends OsSpecificDistributionBuilder { buildContext.ant.fixcrlf(srcdir: "$target/bin", includes: "*.py", eol: "unix") } - private String buildMacZip(String macDistPath, String secondJreSuffix = null) { + private String buildMacZip(String macDistPath) { return buildContext.messages.block("Build zip archive for macOS") { def extraBins = customizer.extraExecutables def allPaths = [buildContext.paths.distAll, macDistPath] String zipRoot = getZipRoot(buildContext, customizer) - String suffix = secondJreSuffix == null ? buildContext.bundledJreManager.jreSuffix() : secondJreSuffix + String suffix = buildContext.bundledJreManager.jreSuffix() def targetPath = "$buildContext.paths.artifacts/${buildContext.productProperties.getBaseArtifactName(buildContext.applicationInfo, buildContext.buildNumber)}${suffix}.mac.zip" buildContext.messages.progress("Building zip archive for macOS") From cf34272833ed25ab4a69e40a8590ae0d44069448 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Feb 2019 12:33:41 +0300 Subject: [PATCH 004/138] Java: More tests for intention to split switch branch with multiple values into separate branches (IDEA-203895) --- .../afterDefalutLabel.java | 15 +++++++++++++++ .../afterNonDefalutLabel.java | 15 +++++++++++++++ .../beforeDefalutLabel.java | 13 +++++++++++++ .../beforeNonDefalutLabel.java | 13 +++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java new file mode 100644 index 000000000000..bda00aa5b0d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterDefalutLabel.java @@ -0,0 +1,15 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + case 2: + s = "x"; + break; + default: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java new file mode 100644 index 000000000000..8f36af144694 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/afterNonDefalutLabel.java @@ -0,0 +1,15 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + default: + case 2: + s = "x"; + break; + case 1: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java new file mode 100644 index 000000000000..d31de7e5a555 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeDefalutLabel.java @@ -0,0 +1,13 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + default: + case 2: + s = "x"; + break; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java new file mode 100644 index 000000000000..cd7e50f833c0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/splitSwitchBranchWithSeveralCaseValues/beforeNonDefalutLabel.java @@ -0,0 +1,13 @@ +// "Copy 'switch' branch" "true" +class C { + void foo(int n) { + String s = ""; + switch (n) { + case 1: + default: + case 2: + s = "x"; + break; + } + } +} \ No newline at end of file From 76d5e03a3a802de8de00a7a0c9d054a7128a86c2 Mon Sep 17 00:00:00 2001 From: Soloveva Anna Date: Sun, 3 Feb 2019 22:36:24 +0300 Subject: [PATCH 005/138] [gui-test] add tests for Google, Boost, Catch test frameworks --- .../com/intellij/testGuiFramework/fixtures/GutterFixture.kt | 6 +++++- .../com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt index 76b420cb8944..7eddff3ee613 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/fixtures/GutterFixture.kt @@ -24,7 +24,9 @@ open class GutterFixture(private val myIde: IdeFrameFixture) { IMPLEMENTATION, IMPLEMENTED, OVERRIDES, - OVERRIDDEN + OVERRIDDEN, + PASSED, + FAILED } val gutterIcons: Map> @@ -52,6 +54,8 @@ open class GutterFixture(private val myIde: IdeFrameFixture) { AllIcons.RunConfigurations.TestState.Run -> result[GutterIcon.RUN_SCRIPT]!!.add(lineNumber) AllIcons.Debugger.Db_set_breakpoint -> result[GutterIcon.BREAKPOINT]!!.add(lineNumber) AllIcons.Debugger.Db_disabled_breakpoint -> result[GutterIcon.DISABLED_BREAKPOINT]!!.add(lineNumber) + AllIcons.RunConfigurations.TestState.Green2 -> result[GutterIcon.PASSED]!!.add(lineNumber) + AllIcons.RunConfigurations.TestState.Red2 -> result[GutterIcon.FAILED]!!.add(lineNumber) else -> handleUnmatchedIcon(icon)?.let { result.getOrDefault(it, mutableListOf(lineNumber)).add(lineNumber) } } } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt index f95c34819aec..ecd85cc2b7d9 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/impl/GuiTestCaseExt.kt @@ -343,6 +343,7 @@ fun GuiTestCase.checkGutterIcons(gutterIcon: GutterFixture.GutterIcon, waitUntilFileIsLoaded() waitUntilErrorAnalysisFinishes() gutter.waitUntilIconsShown(mapOf(gutterIcon to expectedNumberOfIcons)) + moveToLine(expectedNumberOfIcons) } val gutterLinesWithIcon = gutter.linesWithGutterIcon(gutterIcon) val contents = this@editor.getCurrentFileContents(false)?.lines() ?: listOf() From 496b3a357045dc39743dbd1941fcb8ae5a081054 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Mon, 4 Feb 2019 12:38:19 +0300 Subject: [PATCH 006/138] introduce IntRef for convenience --- .../src/com/intellij/openapi/util/IntRef.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 platform/util/src/com/intellij/openapi/util/IntRef.java diff --git a/platform/util/src/com/intellij/openapi/util/IntRef.java b/platform/util/src/com/intellij/openapi/util/IntRef.java new file mode 100644 index 000000000000..3a29df8b8110 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/IntRef.java @@ -0,0 +1,31 @@ +// Copyright 2000-2019 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.openapi.util; + +public class IntRef { + private int myValue; + + public IntRef() { + this(0); + } + + public IntRef(int value) { + myValue = value; + } + + public int get() { + return myValue; + } + + public void set(int value) { + myValue = value; + } + + public void inc() { + myValue++; + } + + @Override + public String toString() { + return "IntRef(" + myValue + ")"; + } +} From 1fd8513825b6b465a676068b0ae83b6fef632bd3 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 10:57:39 +0100 Subject: [PATCH 007/138] switch expression: undefined type for expr without result expressions --- .../psi/impl/source/tree/java/PsiSwitchExpressionImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java index 0f328280b1c4..c86d740befb7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSwitchExpressionImpl.java @@ -46,6 +46,8 @@ public class PsiSwitchExpressionImpl extends PsiSwitchBlockImpl implements PsiSw resultTypes.add(resultExpressionType); } + if (resultTypes.isEmpty()) return null; + //If the result expressions all have the same type (which may be the null type), then that is the type of the switch expression. if (resultTypes.size() == 1) { return ContainerUtil.getFirstItem(resultTypes); From 4a114d92f6c184d0388adaf093b2ebc67aa9bf39 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 10:58:31 +0100 Subject: [PATCH 008/138] introduce variable from yet standalone switch expression (IDEA-206523) --- .../introduceVariable/IntroduceVariableBase.java | 11 ++++++++++- .../FromSwitchStatementJava12Preview.after.java | 8 ++++++++ .../FromSwitchStatementJava12Preview.java | 7 +++++++ .../java/refactoring/IntroduceVariableTest.java | 4 ++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java create mode 100644 java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 94c8cf98a71b..e960e0246f20 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -329,9 +329,18 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { if (statements.length == 1) { if (statements[0] instanceof PsiExpressionStatement) { tempExpr = ((PsiExpressionStatement) statements[0]).getExpression(); - } else if (statements[0] instanceof PsiReturnStatement) { + } + else if (statements[0] instanceof PsiReturnStatement) { tempExpr = ((PsiReturnStatement)statements[0]).getReturnValue(); } + else if (statements[0] instanceof PsiSwitchStatement) { + PsiExpression expr = JavaPsiFacade.getElementFactory(project).createExpressionFromText(statements[0].getText(), statements[0]); + TextRange range = statements[0].getTextRange(); + final RangeMarker rangeMarker = FileDocumentManager.getInstance().getDocument(file.getVirtualFile()).createRangeMarker(range); + expr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker); + expr.putUserData(ElementToWorkOn.PARENT, statements[0]); + return expr; + } } } diff --git a/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java new file mode 100644 index 000000000000..30c3a423b77b --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.after.java @@ -0,0 +1,8 @@ +class MyTest { + { + String temp = switch (0) { + default: + break ""; + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java new file mode 100644 index 000000000000..a6b62ae1ee19 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/FromSwitchStatementJava12Preview.java @@ -0,0 +1,7 @@ +class MyTest { + { + switch (0) { + default: break ""; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java index 73b2c338bea0..a5eee78cba49 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java @@ -259,6 +259,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); } + public void testFromSwitchStatementJava12Preview() { + doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); + } + public void testDeclareTernary() { doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING)); } From 0bca464f14af10cd13b810327842b3a15800beed Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 11:00:08 +0100 Subject: [PATCH 009/138] create file: don't close dialog on cancel file type association (IDEA-206481) --- .../src/com/intellij/ide/actions/CreateFileAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java index b6faa4ff9d9a..3f8764809ea9 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileAction.java @@ -21,6 +21,7 @@ import com.intellij.ide.IdeBundle; import com.intellij.idea.ActionsBundle; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; import com.intellij.openapi.project.DumbAware; @@ -231,10 +232,9 @@ public class CreateFileAction extends CreateElementActionBase implements DumbAwa final PsiDirectory psiDirectory = getDirectory(); final Project project = psiDirectory.getProject(); - final boolean[] result = {false}; - FileTypeChooser.getKnownFileTypeOrAssociate(psiDirectory.getVirtualFile(), getFileName(inputString), project); - result[0] = super.canClose(getFileName(inputString)); - return result[0]; + FileType fileType = FileTypeChooser.getKnownFileTypeOrAssociate(psiDirectory.getVirtualFile(), getFileName(inputString), project); + if (fileType == null) return false; + return super.canClose(getFileName(inputString)); } } } From 71be7ca0f52a323a10ef9fbcc5ee952b8db18f85 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 13:14:19 +0300 Subject: [PATCH 010/138] EA-135766 - assert: AnnotateLocalFileAction.perform Do not report error - IpnbFileType "Jupyter Notebook" is a text file without available TextFileEditor. --- .../openapi/vcs/actions/AnnotateLocalFileAction.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java index a341bb53c695..f39b58c930a6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateLocalFileAction.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.annotate.AnnotationProvider; @@ -99,8 +100,10 @@ public class AnnotateLocalFileAction { } if (editor == null) { - LOG.error(String.format("Can't create text editor for file: valid - %s; file type - %s; editors - %s", - selectedFile.isValid(), selectedFile.getFileType(), Arrays.toString(fileEditors))); + Messages.showErrorDialog(project, "Can't create text editor for " + selectedFile.getPresentableUrl(), + VcsBundle.message("message.title.annotate")); + LOG.warn(String.format("Can't create text editor for file: valid - %s; file type - %s; editors - %s", + selectedFile.isValid(), selectedFile.getFileType().getName(), Arrays.toString(fileEditors))); return; } From b6d95aef3389489e888e88a24df4b0f1be02d4a0 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Feb 2019 11:18:38 +0100 Subject: [PATCH 011/138] IDEA-CR-42816 don't wrap ProcessCanceledException --- .../src/com/intellij/util/ExtensionInstantiator.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java index fbb27610a732..9aabc178fd20 100644 --- a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java +++ b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java @@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.PluginDescriptor; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.progress.ProcessCanceledException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.picocontainer.PicoContainer; @@ -36,6 +37,9 @@ public final class ExtensionInstantiator { try { return ReflectionUtil.newInstance(clazz, false); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { if (e.getCause() instanceof NoSuchMethodException) { LOG.error(new PluginException("Bean extension class constructor must not have parameters: " + className, pluginId)); @@ -48,6 +52,9 @@ public final class ExtensionInstantiator { try { return AbstractExtensionPointBean.instantiate(clazz, picoContainer, true); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw new PluginException(e, pluginId); } From a73a19b5a54298fca86ec86e7b66693b29207381 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Mon, 4 Feb 2019 13:26:33 +0300 Subject: [PATCH 012/138] IDEA-124595 - do regular step out if block is not detected --- .../actions/StepOutOfBlockAction.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java index dccca4e42761..a156222e8b20 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/StepOutOfBlockAction.java @@ -12,8 +12,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiCodeBlock; -import com.intellij.psi.PsiElement; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Range; import com.intellij.xdebugger.XDebugProcess; @@ -45,16 +44,25 @@ public class StepOutOfBlockAction extends DebuggerAction implements DumbAware { SourcePosition position = debuggerContext.getSourcePosition(); if (position != null && session != null) { PsiElement element = position.getElementAt(); - PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); - if (block != null) { - TextRange textRange = block.getTextRange(); - Document document = FileDocumentManager.getInstance().getDocument(position.getFile().getVirtualFile()); - if (document != null) { - int startLine = document.getLineNumber(textRange.getStartOffset()); - int endLine = document.getLineNumber(textRange.getEndOffset()); - session.sessionResumed(); - session.stepOver(false, new BlockFilter(startLine, endLine), StepRequest.STEP_LINE); + PsiElement block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class, PsiLambdaExpression.class); + if (block instanceof PsiCodeBlock) { + PsiElement parent = block.getParent(); + if (parent instanceof PsiMethod || parent instanceof PsiLambdaExpression) { + xSession.stepOut(); } + else { + TextRange textRange = block.getTextRange(); + Document document = FileDocumentManager.getInstance().getDocument(position.getFile().getVirtualFile()); + if (document != null) { + int startLine = document.getLineNumber(textRange.getStartOffset()); + int endLine = document.getLineNumber(textRange.getEndOffset()); + session.sessionResumed(); + session.stepOver(false, new BlockFilter(startLine, endLine), StepRequest.STEP_LINE); + } + } + } + else { + xSession.stepOut(); } } } From 5dc26a2fba1e9ee5c1558eb80665a531d7f80701 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Feb 2019 11:22:14 +0100 Subject: [PATCH 013/138] =?UTF-8?q?InjectedReferencesContributor=20?= =?UTF-8?q?=E2=80=94=20don't=20call=20getExtensions=20in=20extension=20con?= =?UTF-8?q?structor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InjectedReferencesContributor.java | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java index 066a191daa94..f5762bb740c1 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/references/InjectedReferencesContributor.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-2019 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.intellij.plugins.intelliLang.references; import com.intellij.lang.injection.InjectedLanguageManager; @@ -44,11 +30,6 @@ import java.util.List; */ public class InjectedReferencesContributor extends PsiReferenceContributor { private static final Key INJECTED_REFERENCES = Key.create("injected references"); - private final ReferenceInjector[] myExtensions; - - InjectedReferencesContributor() { - myExtensions = ReferenceInjector.EXTENSION_POINT_NAME.getExtensions(); - } public static boolean isInjected(@Nullable PsiReference reference) { return reference != null && reference.getElement().getUserData(INJECTED_REFERENCES) != null; @@ -62,6 +43,7 @@ public class InjectedReferencesContributor extends PsiReferenceContributor { @Override public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + final List extensions = ReferenceInjector.EXTENSION_POINT_NAME.getExtensionList(); registrar.registerReferenceProvider(PlatformPatterns.psiElement(), new PsiReferenceProvider() { @NotNull @Override @@ -70,7 +52,7 @@ public class InjectedReferencesContributor extends PsiReferenceContributor { Project project = element.getProject(); Configuration configuration = Configuration.getProjectInstance(project); final Ref injected = new Ref<>(Boolean.FALSE); - for (ReferenceInjector injector : myExtensions) { + for (ReferenceInjector injector : extensions) { Collection injections = configuration.getInjectionsByLanguageId(injector.getId()); for (BaseInjection injection : injections) { if (injection.acceptForReference(element)) { From 070ebb9cc6e6db21e9460e4dd6010fac49a9ae3e Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 4 Feb 2019 13:28:23 +0300 Subject: [PATCH 014/138] PY-32881 PsiInvalidElementAccessException on editor opening Ensure asynchronous editor loading works correctly when PSI file for editor's document is invalidated without document change --- .../impl/text/PsiAwareTextEditorImpl.java | 37 ++++++++++--------- .../impl/text/AsyncEditorLoader.java | 23 +++++------- .../fileEditor/impl/text/TextEditorImpl.java | 12 +++--- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java index 361de262f16d..9bfe6b5ba376 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorImpl.java @@ -40,8 +40,8 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl { @NotNull @Override - protected Runnable loadEditorInBackground() { - Runnable baseAction = super.loadEditorInBackground(); + protected AsyncEditorLoader.LoadEditorResult loadEditorInBackground() { + AsyncEditorLoader.LoadEditorResult baseResult = super.loadEditorInBackground(); PsiFile psiFile = PsiManager.getInstance(myProject).findFile(myFile); Document document = FileDocumentManager.getInstance().getDocument(myFile); boolean shouldBuildInitialFoldings = @@ -52,25 +52,26 @@ public class PsiAwareTextEditorImpl extends TextEditorImpl { List zones = FocusModePassFactory.calcFocusZones(psiFile); - return () -> { - baseAction.run(); - Editor editor = getEditor(); + return new AsyncEditorLoader.LoadEditorResult(baseResult.continuationValidator.and(d -> psiFile == null || psiFile.isValid()), + () -> { + baseResult.continuation.run(); + Editor editor = getEditor(); - if (foldingState != null) { - foldingState.setToEditor(editor); - } + if (foldingState != null) { + foldingState.setToEditor(editor); + } - if (zones != null) { - FocusModePassFactory.setToEditor(zones, editor); - if (editor instanceof EditorImpl) { - ((EditorImpl)editor).applyFocusMode(); - } - } + if (zones != null) { + FocusModePassFactory.setToEditor(zones, editor); + if (editor instanceof EditorImpl) { + ((EditorImpl)editor).applyFocusMode(); + } + } - if (psiFile != null && psiFile.isValid()) { - DaemonCodeAnalyzer.getInstance(myProject).restart(psiFile); - } - }; + if (psiFile != null && psiFile.isValid()) { + DaemonCodeAnalyzer.getInstance(myProject).restart(psiFile); + } + }); } @NotNull diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index c950a9ef4b29..afb831c46bd0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; +import java.util.function.Predicate; public class AsyncEditorLoader { private static final ExecutorService ourExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncEditorLoader Pool", 2); @@ -116,10 +117,9 @@ public class AsyncEditorLoader { */ private LoadingProgress scheduleLoading() { CompletableFuture continuationFuture = new CompletableFuture<>(); - Document document = myEditor.getDocument(); Future totalProgressFuture = ourExecutor.submit(() -> { while (!myEditorComponent.isDisposed() && !isDone()) { - LoadEditorResult result = tryLoadEditor(document); + LoadEditorResult result = tryLoadEditor(); if (result != null) { continuationFuture.complete(result.continuation); invokeAndWait(() -> { @@ -127,7 +127,7 @@ public class AsyncEditorLoader { // it might happen when the caller already finished the loading manually through `continuationFuture` return; } - if ((myTooLongIndicator.isCanceled() || isCommitted()) && result.docStamp == document.getModificationStamp()) { + if ((myTooLongIndicator.isCanceled() || isCommitted()) && result.continuationValidator.test(myEditor.getDocument())) { loadingFinished(result.continuation); } }); @@ -146,24 +146,21 @@ public class AsyncEditorLoader { return myLoadingFinished.isDone(); } - private static class LoadEditorResult { - final long docStamp; + static class LoadEditorResult { + @NotNull final Predicate continuationValidator; @NotNull final Runnable continuation; - private LoadEditorResult(long docStamp, @NotNull Runnable continuation) { - this.docStamp = docStamp; + LoadEditorResult(@NotNull Predicate continuationValidator, @NotNull Runnable continuation) { + this.continuationValidator = continuationValidator; this.continuation = continuation; } } @Nullable - private LoadEditorResult tryLoadEditor(@NotNull Document document) { + private LoadEditorResult tryLoadEditor() { Ref ref = Ref.create(); - Runnable loadingRunnable = () -> { - Runnable continuation = - myProject.isDisposed() ? EmptyRunnable.INSTANCE : myTextEditor.loadEditorInBackground(); - ref.set(new LoadEditorResult(document.getModificationStamp(), continuation)); - }; + Runnable loadingRunnable = () -> ref.set(myProject.isDisposed() ? new LoadEditorResult(document -> true, EmptyRunnable.INSTANCE) + : myTextEditor.loadEditorInBackground()); if (!myTooLongIndicator.isCanceled()) { ProgressIndicatorUtils.runWithWriteActionPriority( () -> PsiDocumentManager.getInstance(myProject).commitAndRunReadAction(loadingRunnable), diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java index 8f8e746094d1..94a8b64bdd2c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorImpl.java @@ -70,18 +70,18 @@ public class TextEditorImpl extends UserDataHolderBase implements TextEditor { * @return a continuation to be called in EDT */ @NotNull - protected Runnable loadEditorInBackground() { + protected AsyncEditorLoader.LoadEditorResult loadEditorInBackground() { EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(myFile, scheme, myProject); EditorEx editor = (EditorEx)getEditor(); highlighter.setText(editor.getDocument().getImmutableCharSequence()); long stamp = editor.getDocument().getModificationStamp(); Language language = getDocumentLanguage(editor); - return () -> { - LOG.assertTrue(stamp == editor.getDocument().getModificationStamp()); - editor.getSettings().setLanguage(language); - editor.setHighlighter(highlighter); - }; + return new AsyncEditorLoader.LoadEditorResult(document -> stamp == document.getModificationStamp(), + () -> { + editor.getSettings().setLanguage(language); + editor.setHighlighter(highlighter); + }); } @Nullable From f77617e1207ecd928e69ac41eb7f84f8c97bb638 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 12:47:55 +0100 Subject: [PATCH 015/138] tests: don't trim presentation of suites based on startsWith logic (IDEA-206449) --- .../sm/runner/ui/TestsPresentationUtil.java | 2 +- .../sm/runner/ui/TestsPresentationUtilTest.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java index 606919a13c71..3ead3c0aa5e7 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtil.java @@ -204,7 +204,7 @@ public class TestsPresentationUtil { } String presentationCandidate = name; - if (parent != null) { + if (parent != null && !testProxy.isSuite()) { String parentName = parent.getName(); if (parentName != null) { boolean parentStartsWith = name.startsWith(parentName); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java index be492214c0d7..0cbac72f76bd 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java @@ -533,6 +533,23 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase { assertEquals(PoolOfTestIcons.PASSED_ICON, renderer2.getIcon()); } + public void testPresentationWithDependentNamesTestProxy() { + SMTestProxy suiteProxy = createSuiteProxy("A"); + SMTestProxy testProxy = createTestProxy("A.b"); + suiteProxy.addChild(testProxy); + TestsPresentationUtil.formatTestProxy(testProxy, myRenderer); + assertEquals("b", myFragContainer.getTextAt(0)); + } + + public void testPresentationWithDependentNamesSuite() { + SMTestProxy suiteProxy = createSuiteProxy("A"); + SMTestProxy suiteProxyChild = createSuiteProxy("AB"); + suiteProxy.addChild(suiteProxyChild); + TestsPresentationUtil.formatTestProxy(suiteProxyChild, myRenderer); + assertEquals("AB", myFragContainer.getTextAt(0)); + myRenderer.clear(); + } + public void testFormatRootNodeWithoutChildren() { TestsPresentationUtil.formatRootNodeWithoutChildren(mySMRootTestProxy, myRenderer); From 5a3dc52939db1736e6afbdc91e74e7231572cd1b Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 1 Feb 2019 13:48:33 +0300 Subject: [PATCH 016/138] IDEA-206431: ToolWindow must fire StateChanged event on deactivation --- .../src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java index a98e1393c83b..c23eef2b9264 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.java @@ -195,7 +195,7 @@ public class ToolWindowManagerImpl extends ToolWindowManagerEx implements Persis .handleFocusLostOnPinned(toolWindowId -> { List commands = new ArrayList<>(); deactivateToolWindowImpl(getRegisteredInfoOrLogError(toolWindowId), true, commands); - myCommandProcessor.execute(commands, myProject.getDisposed()); + execute(commands, true); // notify clients that toolwindow is deactivated }) .handleWindowed(toolWindowId -> {}) .bind(myProject); From b1cd96dcdd098c221a73aff4d40d81acb04166c9 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 1 Feb 2019 13:56:55 +0300 Subject: [PATCH 017/138] IDEA-206431: add SelectInContext.selectIn method --- .../FavoritesAutoscrollFromSourceHandler.java | 6 +----- .../ide/impl/ProjectViewSelectInGroupTarget.java | 4 +++- .../ide/projectView/impl/ProjectViewImpl.java | 4 ++-- .../src/com/intellij/ide/SelectInContext.java | 11 +++++++++++ .../openapi/fileEditor/OpenFileDescriptor.java | 5 +---- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java index affef9d98712..298fd23928a7 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesAutoscrollFromSourceHandler.java @@ -50,10 +50,6 @@ public class FavoritesAutoscrollFromSourceHandler extends AutoScrollFromSourceHa protected void selectElementFromEditor(@NotNull FileEditor editor) { VirtualFile file = FileEditorManagerEx.getInstanceEx(myProject).getFile(editor); PsiFile psiFile = file == null ? null : PsiManager.getInstance(myProject).findFile(file); - if (psiFile == null) return; - FileEditorSelectInContext context = new FileEditorSelectInContext(editor, psiFile); - if (mySelectInTarget.canSelect(context)) { - mySelectInTarget.selectIn(context, false); - } + if (psiFile != null) new FileEditorSelectInContext(editor, psiFile).selectIn(mySelectInTarget, false); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java index 1c47070f8d2f..a3738e45dfac 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/ProjectViewSelectInGroupTarget.java @@ -48,7 +48,9 @@ public class ProjectViewSelectInGroupTarget implements CompositeSelectInTarget, } } targetsToCheck.addAll(targets); - targetsToCheck.stream().filter(t -> t.canSelect(context)).findFirst().ifPresent(target -> target.selectIn(context, requestFocus)); + for (SelectInTarget target : targetsToCheck) { + if (context.selectIn(target, requestFocus)) break; + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 4130c79bb2bb..f51e337b3614 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -1978,8 +1978,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo void selectInCurrentTarget() { SelectInTarget target = getCurrentSelectInTarget(); - if (target != null && getPsiFile() != null && target.canSelect(this)) { - target.selectIn(this, false); + if (target != null && getPsiFile() != null) { + selectIn(target, false); } } } diff --git a/platform/platform-api/src/com/intellij/ide/SelectInContext.java b/platform/platform-api/src/com/intellij/ide/SelectInContext.java index 0ed1282037f5..a57cc553454b 100644 --- a/platform/platform-api/src/com/intellij/ide/SelectInContext.java +++ b/platform/platform-api/src/com/intellij/ide/SelectInContext.java @@ -38,4 +38,15 @@ public interface SelectInContext { @Nullable FileEditorProvider getFileEditorProvider(); + + /** + * @param target an object that supports a context selection + * @param requestFocus specifies whether a focus request is needed or not + * @return {@code true} if a selection request is approved and executed by the given target + */ + default boolean selectIn(@NotNull SelectInTarget target, boolean requestFocus) { + if (!target.canSelect(this)) return false; + target.selectIn(this, requestFocus); + return true; + } } \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java index 5ccd0deec282..3ffc591d4d17 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java @@ -167,10 +167,7 @@ public class OpenFileDescriptor implements Navigatable, Comparable Date: Mon, 4 Feb 2019 03:34:32 +0300 Subject: [PATCH 018/138] IDEA-206431: ignore first selection on window showing if another selection is requested --- .../ide/projectView/impl/ProjectViewImpl.java | 158 ++++++++++-------- 1 file changed, 85 insertions(+), 73 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index f51e337b3614..2ce0bc383588 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -137,6 +137,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo private final AutoScrollToSourceHandler myAutoScrollToSourceHandler; private final MyAutoScrollFromSourceHandler myAutoScrollFromSourceHandler; + private volatile ThreeState myCurrentSelectionObsolete = ThreeState.NO; private final IdeView myIdeView = new IdeViewForProjectViewPane(this::getCurrentProjectViewPane); private final MyDeletePSIElementProvider myDeletePSIElementProvider = new MyDeletePSIElementProvider(); @@ -212,7 +213,8 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override public void stateChanged() { ToolWindow window = toolWindowManager.getToolWindow(ToolWindowId.PROJECT_VIEW); - if (window == null) return; + if (window == null || toolWindowVisible == window.isVisible()) return; + myCurrentSelectionObsolete = ThreeState.NO; if (window.isVisible() && !toolWindowVisible) { String id = getCurrentViewId(); AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); @@ -221,7 +223,11 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo myAutoScrollToSourceHandler.onMouseClicked(currentProjectViewPane.getTree()); } if (isAutoscrollFromSource(id)) { - myAutoScrollFromSourceHandler.setAutoScrollEnabled(true); + SimpleSelectInContext context = myAutoScrollFromSourceHandler.findSelectInContext(); + if (context != null) { + myCurrentSelectionObsolete = ThreeState.UNSURE; + context.selectInCurrentTarget(); + } } } } @@ -768,8 +774,20 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo } } + private boolean isCurrentSelectionObsolete(boolean requestFocus) { + if (myCurrentSelectionObsolete == ThreeState.YES) { + myCurrentSelectionObsolete = ThreeState.NO; + return true; + } + if (myCurrentSelectionObsolete == ThreeState.UNSURE) { + myCurrentSelectionObsolete = requestFocus ? ThreeState.YES : ThreeState.NO; + } + return false; + } + @Override public void select(final Object element, VirtualFile file, boolean requestFocus) { + if (isCurrentSelectionObsolete(requestFocus)) return; final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); if (viewPane != null) { viewPane.select(element, file, requestFocus); @@ -779,6 +797,7 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @NotNull @Override public ActionCallback selectCB(Object element, VirtualFile file, boolean requestFocus) { + if (isCurrentSelectionObsolete(requestFocus)) return ActionCallback.REJECTED; final AbstractProjectViewPane viewPane = getCurrentProjectViewPane(); if (viewPane instanceof AbstractProjectViewPSIPane) { return ((AbstractProjectViewPSIPane)viewPane).selectCB(element, file, requestFocus); @@ -1317,7 +1336,6 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override public void selectPsiElement(@NotNull PsiElement element, boolean requestFocus) { - if (element == null) return; VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element); select(element, virtualFile, requestFocus); } @@ -1871,38 +1889,37 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override protected void selectElementFromEditor(@NotNull FileEditor fileEditor) { if (myProject.isDisposed() || !myViewContentPanel.isShowing()) return; - if (isAutoscrollFromSource(getCurrentViewId())) { - if (fileEditor instanceof TextEditor) { - TextEditor textEditor = (TextEditor)fileEditor; - selectElementAtCaretNotLosingFocus(textEditor.getEditor()); - } - else { - PsiFile psiFile = getPsiFile(getVirtualFile(fileEditor)); - if (psiFile != null) { - new MySelectInContext(psiFile, null).selectInCurrentTarget(); - } - } + if (isAutoscrollFromSource(getCurrentViewId()) && !isCurrentProjectViewPaneFocused()) { + SimpleSelectInContext context = getSelectInContext(fileEditor); + if (context != null) context.selectInCurrentTarget(); } } void scrollFromSource() { - FileEditorManager manager = FileEditorManager.getInstance(myProject); - if (scrollFromSource(manager.getSelectedEditor())) return; - for (FileEditor fileEditor : manager.getSelectedEditors()) { - if (scrollFromSource(fileEditor)) return; - } + SimpleSelectInContext context = findSelectInContext(); + if (context != null) context.selectInCurrentTarget(); } - private boolean scrollFromSource(FileEditor fileEditor) { + @Nullable + SimpleSelectInContext findSelectInContext() { + SimpleSelectInContext context = getSelectInContext(myFileEditorManager.getSelectedEditor()); + if (context != null) return context; + for (FileEditor fileEditor : myFileEditorManager.getSelectedEditors()) { + context = getSelectInContext(fileEditor); + if (context != null) return context; + } + return null; + } + + @Nullable + private SimpleSelectInContext getSelectInContext(@Nullable FileEditor fileEditor) { if (fileEditor instanceof TextEditor) { TextEditor textEditor = (TextEditor)fileEditor; - selectElementAtCaret(textEditor.getEditor()); - return true; + PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(textEditor.getEditor().getDocument()); + return psiFile == null ? null : new EditorSelectInContext(psiFile, textEditor.getEditor()); } PsiFile psiFile = getPsiFile(getVirtualFile(fileEditor)); - if (psiFile == null) return false; - scrollFromFile(psiFile, null); - return true; + return psiFile == null ? null : new SimpleSelectInContext(psiFile); } private PsiFile getPsiFile(VirtualFile file) { @@ -1913,23 +1930,9 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo return fileEditor == null ? null : FileEditorManagerEx.getInstanceEx(myProject).getFile(fileEditor); } - private void selectElementAtCaretNotLosingFocus(@NotNull Editor editor) { + private boolean isCurrentProjectViewPaneFocused() { AbstractProjectViewPane pane = getCurrentProjectViewPane(); - if (pane != null && !IJSwingUtilities.hasFocus(pane.getComponentToFocus())) { - selectElementAtCaret(editor); - } - } - - private void selectElementAtCaret(@NotNull Editor editor) { - final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); - if (file == null) return; - - scrollFromFile(file, editor); - } - - private void scrollFromFile(@NotNull PsiFile file, @Nullable Editor editor) { - MySelectInContext selectInContext = new MySelectInContext(file, editor); - PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted(selectInContext::selectInCurrentTarget); + return pane != null && IJSwingUtilities.hasFocus(pane.getComponentToFocus()); } @Override @@ -1940,48 +1943,57 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo @Override protected void setAutoScrollEnabled(boolean state) { setAutoscrollFromSource(state, myCurrentViewId); - if (state) { - final Editor editor = myFileEditorManager.getSelectedTextEditor(); - if (editor != null) { - selectElementAtCaretNotLosingFocus(editor); - } + if (state && !isCurrentProjectViewPaneFocused()) { + scrollFromSource(); } createToolbarActions(); } + } - private class MySelectInContext extends SmartSelectInContext { - @Nullable private final Editor myEditor; + private class SimpleSelectInContext extends SmartSelectInContext { + SimpleSelectInContext(@NotNull PsiFile psiFile) { + super(psiFile, psiFile); + } - private MySelectInContext(@NotNull PsiFile psiFile, @Nullable Editor editor) { - super(psiFile, psiFile); - myEditor = editor; + void selectInCurrentTarget() { + SelectInTarget target = getCurrentSelectInTarget(); + if (target != null && getPsiFile() != null) { + selectIn(target, false); } + } - @Override - @NotNull - public FileEditorProvider getFileEditorProvider() { - return () -> ArrayUtil.getFirstElement(myFileEditorManager.openFile(getVirtualFile(), false)); - } + @Override + @NotNull + public FileEditorProvider getFileEditorProvider() { + return () -> ArrayUtil.getFirstElement(myFileEditorManager.openFile(getVirtualFile(), false)); + } + } - @Override - public Object getSelectorInFile() { - PsiFile file = getPsiFile(); - if (file != null && myEditor != null) { - final int offset = myEditor.getCaretModel().getOffset(); - PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); - if (manager.hasUncommitedDocuments()) manager.commitAllDocuments(); - PsiElement element = file.findElementAt(offset); - if (element != null) return element; - } - return file; - } + private class EditorSelectInContext extends SimpleSelectInContext { + private final Editor editor; - void selectInCurrentTarget() { - SelectInTarget target = getCurrentSelectInTarget(); - if (target != null && getPsiFile() != null) { - selectIn(target, false); - } + EditorSelectInContext(@NotNull PsiFile psiFile, @NotNull Editor editor) { + super(psiFile); + this.editor = editor; + } + + @Override + void selectInCurrentTarget() { + PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); + if (manager != null) manager.performLaterWhenAllCommitted(super::selectInCurrentTarget); + } + + @Override + public Object getSelectorInFile() { + PsiFile file = getPsiFile(); + if (file != null) { + int offset = editor.getCaretModel().getOffset(); + PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject()); + if (manager.hasUncommitedDocuments()) manager.commitAllDocuments(); + PsiElement element = file.findElementAt(offset); + if (element != null) return element; } + return file; } } From 7f4d2c88c0968be3c9806aaa6b25b1765c4a4758 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 13:57:58 +0300 Subject: [PATCH 019/138] Do not open a forgotten selection on opening a project view --- .../ide/projectView/impl/ProjectViewImpl.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java index 2ce0bc383588..55122ccd7579 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewImpl.java @@ -216,18 +216,12 @@ public class ProjectViewImpl extends ProjectView implements PersistentStateCompo if (window == null || toolWindowVisible == window.isVisible()) return; myCurrentSelectionObsolete = ThreeState.NO; if (window.isVisible() && !toolWindowVisible) { - String id = getCurrentViewId(); AbstractProjectViewPane currentProjectViewPane = getCurrentProjectViewPane(); - if (currentProjectViewPane != null) { - if (isAutoscrollToSource(id)) { - myAutoScrollToSourceHandler.onMouseClicked(currentProjectViewPane.getTree()); - } - if (isAutoscrollFromSource(id)) { - SimpleSelectInContext context = myAutoScrollFromSourceHandler.findSelectInContext(); - if (context != null) { - myCurrentSelectionObsolete = ThreeState.UNSURE; - context.selectInCurrentTarget(); - } + if (currentProjectViewPane != null && isAutoscrollFromSource(currentProjectViewPane.getId())) { + SimpleSelectInContext context = myAutoScrollFromSourceHandler.findSelectInContext(); + if (context != null) { + myCurrentSelectionObsolete = ThreeState.UNSURE; + context.selectInCurrentTarget(); } } } From 58fc570d03f6f73e0c9965681741bd09c89e2890 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 14:29:57 +0300 Subject: [PATCH 020/138] Add new icon for UX-489 --- platform/icons/src/actions/stepOutCodeBlock.svg | 10 ++++++++++ platform/icons/src/actions/stepOutCodeBlock_dark.svg | 10 ++++++++++ platform/util/src/com/intellij/icons/AllIcons.java | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 platform/icons/src/actions/stepOutCodeBlock.svg create mode 100644 platform/icons/src/actions/stepOutCodeBlock_dark.svg diff --git a/platform/icons/src/actions/stepOutCodeBlock.svg b/platform/icons/src/actions/stepOutCodeBlock.svg new file mode 100644 index 000000000000..a8ac444c7e68 --- /dev/null +++ b/platform/icons/src/actions/stepOutCodeBlock.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/platform/icons/src/actions/stepOutCodeBlock_dark.svg b/platform/icons/src/actions/stepOutCodeBlock_dark.svg new file mode 100644 index 000000000000..70fb551bba1e --- /dev/null +++ b/platform/icons/src/actions/stepOutCodeBlock_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index 941b376cc8be..fea431de0d13 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -484,6 +484,10 @@ public class AllIcons { * 16x16 */ public static final Icon StepOut = IconLoader.getIcon("/actions/stepOut.svg"); + /** + * 16x16 + */ + public static final Icon StepOutCodeBlock = IconLoader.getIcon("/actions/stepOutCodeBlock.svg"); /** * 16x16 */ From f23e0f4e330e0ac3fad42ead4186b839cde7da1e Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Mon, 4 Feb 2019 15:04:18 +0300 Subject: [PATCH 021/138] avoid project leak in tests --- .../execution/impl/DefaultJavaProgramRunner.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index d69953e5cb14..eede8ff52145 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -282,11 +282,13 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { myProcessHandler.addProcessListener(new ProcessAdapter() { @Override public void startNotified(@NotNull ProcessEvent event) { - // 1 second delay to allow jvm to start correctly - JobScheduler.getScheduler() - .schedule(() -> myEnabled.set(!myProcessHandler.isProcessTerminating() && !myProcessHandler.isProcessTerminated() && - JavaDebuggerAttachUtil.canAttach(OSProcessUtil.getProcessID(myProcessHandler.getProcess()))), - 1, TimeUnit.SECONDS); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + // 1 second delay to allow jvm to start correctly + JobScheduler.getScheduler() + .schedule(() -> myEnabled.set(!myProcessHandler.isProcessTerminating() && !myProcessHandler.isProcessTerminated() && + JavaDebuggerAttachUtil.canAttach(OSProcessUtil.getProcessID(myProcessHandler.getProcess()))), + 1, TimeUnit.SECONDS); + } } @Override From bf3d4de4d873b1f5cfe2ee9dceadf053b23d76a0 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 13:06:32 +0100 Subject: [PATCH 022/138] todo view: checkCanceled on traversing tree (IDEA-206539) --- platform/lang-impl/src/com/intellij/ide/todo/FileTree.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java b/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java index 69c39b0f5b2e..a2e813614c68 100644 --- a/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java +++ b/platform/lang-impl/src/com/intellij/ide/todo/FileTree.java @@ -16,6 +16,7 @@ package com.intellij.ide.todo; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; @@ -210,8 +211,11 @@ final class FileTree { List children = myDirectory2Children.get(dir); if (children != null) { for (VirtualFile child : children) { + ProgressManager.checkCanceled(); if (!child.isDirectory()) { - LOG.assertTrue(!filesList.contains(child)); + if (LOG.isDebugEnabled()) { + LOG.assertTrue(!filesList.contains(child)); + } filesList.add(child); } else { From 2426910198708d2797242a689dd100b73df71233 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Mon, 21 Jan 2019 17:35:48 +0300 Subject: [PATCH 023/138] IDEA-205679 Rework validation in tables. Test version. --- .../src/com/intellij/ide/HelpTooltip.java | 2 +- .../src/com/intellij/ui/TableCellState.java | 23 +- .../internal/ui/ComponentPanelTestAction.java | 244 ++++++++++++++++-- 3 files changed, 238 insertions(+), 31 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ide/HelpTooltip.java b/platform/platform-api/src/com/intellij/ide/HelpTooltip.java index 464f88717b7f..af32d915cb50 100644 --- a/platform/platform-api/src/com/intellij/ide/HelpTooltip.java +++ b/platform/platform-api/src/com/intellij/ide/HelpTooltip.java @@ -68,7 +68,7 @@ import java.util.Map; * *

No HTML tagging is allowed in title or shortcut, they are supposed to be simple text strings.

*

Description is can be html formatted. You can use all possible html tagging in description just without enclosing - * <html> and </html> tags themselves. In description it's allowed to have <p/ or <p> tags between paragraphs. + * <html> and </html> tags themselves. In description it's allowed to have <p/> or <p> tags between paragraphs. * Paragraphs will be rendered with the standard (10px) offset from the title, from one another and from the link. * To force the line break in a paragraph use <br/>. Standard font coloring and styling is also available.

* diff --git a/platform/platform-api/src/com/intellij/ui/TableCellState.java b/platform/platform-api/src/com/intellij/ui/TableCellState.java index f7ee2a8af931..091907030221 100644 --- a/platform/platform-api/src/com/intellij/ui/TableCellState.java +++ b/platform/platform-api/src/com/intellij/ui/TableCellState.java @@ -15,9 +15,6 @@ */ package com.intellij.ui; -import com.intellij.util.ui.JBEmptyBorder; -import com.intellij.util.ui.UIUtil; - import javax.swing.*; import javax.swing.border.Border; import java.awt.*; @@ -42,15 +39,23 @@ public class TableCellState { myBackground = table.getBackground(); } - Border border = UIUtil.getTableFocusCellHighlightBorder(); if (hasFocus) { - myCellBorder = border; - if (table.isCellEditable(row, column)) { - myForeground = UIUtil.getTableFocusCellForeground(); - myBackground = UIUtil.getTableFocusCellBackground(); + Border border = null; + if (isSelected) { + border = UIManager.getBorder("Table.focusSelectedCellHighlightBorder"); } + if (border == null) { + border = UIManager.getBorder("Table.focusCellHighlightBorder"); + } + + myCellBorder = border; + + //if (table.isCellEditable(row, column)) { + // myForeground = UIUtil.getTableFocusCellForeground(); + // myBackground = UIUtil.getTableFocusCellBackground(); + //} } else { - myCellBorder = new JBEmptyBorder(border.getBorderInsets(null)); + myCellBorder = UIManager.getBorder("Table.cellNoFocusBorder"); } } diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index d257d3d6cfff..659190f1cd9c 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -1,6 +1,7 @@ // 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.internal.ui; +import com.intellij.icons.AllIcons; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ModalityState; @@ -15,6 +16,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTabbedPane; +import com.intellij.ui.components.fields.ExtendableTextComponent; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.ui.components.labels.DropDownLink; import com.intellij.ui.table.JBTable; import com.intellij.util.Alarm; @@ -30,8 +33,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.HyperlinkEvent; +import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import java.awt.*; import java.net.MalformedURLException; @@ -80,6 +85,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "abracadabra")); private static final String[] STRING_VALUES = { "One", "Two", "Three", "Four", "Five", "Six" }; + private static final SimpleTextAttributes WARNING_CELL_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_WAVED, null); private final Alarm myAlarm = new Alarm(getDisposable()); private ProgressTimerRequest progressTimerRequest; @@ -211,14 +217,14 @@ public class ComponentPanelTestAction extends DumbAwareAction { cp.setCommentText(text); } - ComponentValidator.getInstance(text1).ifPresent(v -> v.revalidate()); + ComponentValidator.getInstance(text1).ifPresent(ComponentValidator::revalidate); } }); text2.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { - ComponentValidator.getInstance(text2).ifPresent(v -> v.revalidate()); + ComponentValidator.getInstance(text2).ifPresent(ComponentValidator::revalidate); } }); @@ -261,38 +267,104 @@ public class ComponentPanelTestAction extends DumbAwareAction { public boolean isCellEditable(int row, int column) { return true; } @Override public void setValueAt(Object value, int row, int col) { - if (col == 0 && ALLOWED_VALUES.contains(value.toString()) || col == 1) { + if (col == 0 || col == 1) { data[row][col] = value.toString(); fireTableCellUpdated(row, col); } } }); - JTextField cellEditor = new JTextField(); + ExtendableTextField cellEditor = new ExtendableTextField(); + ExtendableTextComponent.Extension browseExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + "Open file", () -> System.out.println("Table browse clicked")); + ExtendableTextComponent.Extension errorExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, "Value not allowed", () -> System.out.println("Error clicked")); + cellEditor.addExtension(browseExtension); + cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); cellEditor.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { - Object op = ALLOWED_VALUES.contains(cellEditor.getText()) ? null : "error"; - cellEditor.putClientProperty("JComponent.outline", op); + if (ALLOWED_VALUES.contains(cellEditor.getText())) { + cellEditor.putClientProperty("JComponent.outline", null); + cellEditor.removeExtension(errorExtension); + } + else if (cellEditor.getClientProperty("JComponent.outline") == null) { + cellEditor.putClientProperty("JComponent.outline", "error"); + cellEditor.addExtension(errorExtension); + } } }); - - TableColumn col0 = table.getColumnModel().getColumn(0); - col0.setCellEditor(new DefaultCellEditor(cellEditor)); - col0.setCellRenderer(new DefaultTableCellRenderer() { - @Override - public Dimension getPreferredSize() { - Dimension size = super.getPreferredSize(); - Dimension editorSize = cellEditor.getPreferredSize(); - size.height = Math.max(size.height, editorSize.height); - return size; - } - }); + TableColumn col = table.getColumnModel().getColumn(0); + col.setCellEditor(new DefaultCellEditor(cellEditor)); + col.setCellRenderer(new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). + bindToEditor(cellEditor). + withCellValidator((value, row, column) -> value == null ? ValidationResult.ERROR : + ALLOWED_VALUES.contains(value.toString()) ? + ValidationResult.OK : + ValidationResult.asError("Illegal value: " + value.toString()))); JComboBox rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); - table.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(rightEditor)); + col = table.getColumnModel().getColumn(1); + + col.setCellEditor(new DefaultCellEditor(rightEditor)); + col.setCellRenderer(new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { + + { setIpad(JBUI.emptyInsets()); } // Reset standard pads + + @Override + protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, + boolean hasFocus, int row, int column) { + if (value == null) { + append("No data", SimpleTextAttributes.ERROR_ATTRIBUTES); + } + else { + try { + int iv = Integer.parseInt(value.toString()); + append("value ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); + append(value.toString(), iv <= 8 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : WARNING_CELL_ATTRIBUTES); + } catch (NumberFormatException nfe) { + append(value.toString(), SimpleTextAttributes.ERROR_ATTRIBUTES); + } + } + } + }).bindToEditor(rightEditor). + withCellValidator((value, row, column) -> { + if (value == null) return ValidationResult.ERROR; + else { + try { + int iv = Integer.parseInt(value.toString()); + return iv <= 8 ? ValidationResult.OK : ValidationResult.asWarning("Value " + value.toString() + " is not preferred"); + } catch (NumberFormatException nfe) { + return ValidationResult.ERROR; + } + } + })); + + //col.setCellRenderer(new ColoredTableCellRenderer() { + // { + // setIpad(JBUI.emptyInsets()); + // } + // + // @Override + // protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, + // boolean hasFocus, int row, int column) { + // if (value == null) { + // append("No data", SimpleTextAttributes.ERROR_ATTRIBUTES); + // } + // else { + // try { + // int iv = Integer.parseInt(value.toString()); + // append("value ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); + // append(value.toString(), iv % 2 == 1 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : WARNING_CELL_ATTRIBUTES); + // } catch (NumberFormatException nfe) { + // append(value.toString(), SimpleTextAttributes.ERROR_ATTRIBUTES); + // } + // } + // } + //}); JBScrollPane pane = new JBScrollPane(table); pane.setPreferredSize(JBUI.size(400, 300)); @@ -327,11 +399,11 @@ public class ComponentPanelTestAction extends DumbAwareAction { withLabel("&Host:").withComment("Host comment")). add(UI.PanelFactory.panel(new JComboBox<>(new String[]{"HTTP", "HTTPS", "FTP", "SSL"})). - withLabel("P&rotocol:").withComment("Protocol comment").withTooltip("Protocol selection"). + withLabel("P&rotocol:").withTooltip("Protocol selection"). withTooltipLink("Check here for more info", ()-> System.out.println("More info"))). add(UI.PanelFactory.panel(new ComponentWithBrowseButton<>(new JTextField(), (e) -> System.out.println("Browse for text"))). - withLabel("&Text field:").withComment("Text field comment")). + withLabel("&Text field:").withComment("Text field comment with link")). add(UI.PanelFactory.panel(cbb). withLabel("&Combobox selection:")). @@ -421,6 +493,23 @@ public class ComponentPanelTestAction extends DumbAwareAction { .withValidator(() -> comboBox.getSelectedIndex() % 2 == 0 ? new ValidationInfo("Can't select odd items", comboBox) : null) .installOn(comboBox); + // Extendable ComboBox + ExtendableTextComponent.Extension browseExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, + "Open file", () -> System.out.println("Browse file clicked")); + + ComboBox eComboBox = new ComboBox<>(STRING_VALUES); + eComboBox.setEditable(true); + eComboBox.setEditor(new BasicComboBoxEditor(){ + @Override + protected JTextField createEditorComponent() { + ExtendableTextField ecbEditor = new ExtendableTextField(); + ecbEditor.addExtension(browseExtension); + ecbEditor.setBorder(null); + return ecbEditor; + } + }); + // Panels factory return UI.PanelFactory.grid(). add(UI.PanelFactory.panel(tfbb). @@ -432,6 +521,9 @@ public class ComponentPanelTestAction extends DumbAwareAction { add(UI.PanelFactory.panel(comboBox). withLabel("&ComboBoxEditorTextField:").withComment("EditorComboBox editor")). + add(UI.PanelFactory.panel(eComboBox). + withLabel("ComboBox &extendable:").withComment("ComboBox with ExtendableTextEditor")). + createPanel(); } @@ -577,5 +669,115 @@ public class ComponentPanelTestAction extends DumbAwareAction { return JBUI.Panels.simplePanel().addToTop(panel); } + + public static class ValidationResult { + public static final ValidationResult OK = new ValidationResult(State.Ok, null); + public static final ValidationResult ERROR = new ValidationResult(State.Error, null); + public static final ValidationResult WARNING = new ValidationResult(State.Warning, null); + + public static ValidationResult asError(@NotNull String tooltip) { + return new ValidationResult(State.Error, tooltip); + } + + public static ValidationResult asWarning(@NotNull String tooltip) { + return new ValidationResult(State.Warning, tooltip); + } + + public enum State { + Ok, Warning, Error + } + + @NotNull private final State state; + @Nullable private final String tooltip; + + private ValidationResult(@NotNull State state, @Nullable String tooltip) { + this.state = state; + this.tooltip = tooltip; + } + + @NotNull + public State getState() { + return state; + } + + @Nullable + public String getTooltipText() { + return tooltip; + } + } + + public interface CellValidator { + ValidationResult apply(@Nullable Object value, int row, int col); + } + + public static class ValidatingTableCellRendererWrapper extends CellRendererPanel implements TableCellRenderer { + private final TableCellRenderer delegate; + private final JLabel iconLabel = new JLabel(); + + private JComponent cellEditor; + private CellValidator cellValidator; + + public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { + this.delegate = delegate; + setLayout(new BorderLayout(0, 0)); + add(iconLabel, BorderLayout.EAST); + + iconLabel.setOpaque(false); + iconLabel.setBorder(JBUI.Borders.emptyRight(6)); + setOpaque(true); + setName("Table.cellRenderer"); + } + + public ValidatingTableCellRendererWrapper bindToEditor(@NotNull JComponent cellEditor) { + this.cellEditor = cellEditor; + return this; + } + + public ValidatingTableCellRendererWrapper withCellValidator(CellValidator cellValidator) { + this.cellValidator = cellValidator; + return this; + } + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + if (cellEditor != null) { + Dimension editorSize = cellEditor.getPreferredSize(); + size.height = Math.max(size.height, editorSize.height); + } + + return size; + } + + @Override + public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (cellValidator != null) { + ValidationResult result = cellValidator.apply(value, row, column); + switch (result.getState()) { + case Ok: + iconLabel.setIcon(null); + break; + case Error: + iconLabel.setIcon(AllIcons.General.BalloonError); + break; + case Warning: + iconLabel.setIcon(AllIcons.General.BalloonWarning); + break; + } + setToolTipText(result.getTooltipText()); + } + + JComponent delegateRenderer = (JComponent)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + add(delegateRenderer, BorderLayout.CENTER); + setBorder(delegateRenderer.getBorder()); + delegateRenderer.setBorder(null); + + setBackground(delegateRenderer.getBackground()); + + setSelected(isSelected); + return this; + } + } } } From a8a9ca709c7b5cb1dc0c7f756209cf368bef1513 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Fri, 25 Jan 2019 16:08:41 +0300 Subject: [PATCH 024/138] IDEA-205679 Modified interfaces. Enabled hyperlinks in tooltips. --- .../openapi/ui/ComponentValidator.java | 97 +++++---- .../cellvalidators/CellComponentProvider.java | 61 ++++++ .../ui/cellvalidators/CellTooltipManager.java | 172 ++++++++++++++++ .../ValidatingTableCellRendererWrapper.java | 72 +++++++ .../internal/ui/ComponentPanelTestAction.java | 194 ++++-------------- 5 files changed, 399 insertions(+), 197 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java b/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java index 1cfbc1772d92..244a70247b88 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java @@ -201,47 +201,11 @@ public class ComponentValidator { } if (StringUtil.isNotEmpty(validationInfo.message)) { - JEditorPane tipComponent = new JEditorPane(); - View v = BasicHTML.createHTMLView(tipComponent, String.format("%s", validationInfo.message)); - String text = v.getPreferredSpan(View.X_AXIS) > MAX_WIDTH.get() ? - String.format("
%s
", MAX_WIDTH.get(), validationInfo.message) : - String.format("
%s
", validationInfo.message); - - tipComponent.setContentType("text/html"); - tipComponent.setEditable(false); - tipComponent.addHyperlinkListener(hyperlinkListener); - tipComponent.setEditorKit(UIUtil.getHTMLEditorKit()); - - EditorKit kit = tipComponent.getEditorKit(); - if (kit instanceof HTMLEditorKit) { - StyleSheet css = ((HTMLEditorKit)kit).getStyleSheet(); - - css.addRule("a, a:link {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkColor()) + ";}"); - css.addRule("a:visited {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkVisitedColor()) + ";}"); - css.addRule("a:hover {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkHoverColor()) + ";}"); - css.addRule("a:active {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkPressedColor()) + ";}"); - css.addRule("body {background-color:#" + ColorUtil.toHex(validationInfo.warning ? warningBackgroundColor() : errorBackgroundColor()) + ";}"); - } - - if (tipComponent.getCaret() instanceof DefaultCaret) { - ((DefaultCaret)tipComponent.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); - } - - tipComponent.setCaretPosition(0); - tipComponent.setText(text); - - tipComponent.setBackground(validationInfo.warning ? warningBackgroundColor() : errorBackgroundColor()); - tipComponent.setOpaque(true); - tipComponent.setBorder(getBorder()); - tipComponent.addMouseListener(new TipComponentMouseListener()); - - popupSize = tipComponent.getPreferredSize(); - - popupBuilder = JBPopupFactory.getInstance().createComponentPopupBuilder(tipComponent, null). - setBorderColor(validationInfo.warning ? warningBorderColor() : errorBorderColor()). - setCancelOnClickOutside(false). - setCancelOnMouseOutCallback(e -> e.getID() == MouseEvent.MOUSE_PRESSED && !withinComponent(e)). - setShowShadow(false); + popupBuilder = createPopupBuilder(validationInfo, tipComponent -> { + tipComponent.addHyperlinkListener(hyperlinkListener); + tipComponent.addMouseListener(new TipComponentMouseListener()); + popupSize = tipComponent.getPreferredSize(); + }); getFocusable(validationInfo.component).ifPresent(fc -> { if (fc.hasFocus()) { @@ -253,9 +217,54 @@ public class ComponentValidator { } } - private boolean withinComponent(@NotNull MouseEvent e) { - if (validationInfo != null && validationInfo.component != null && validationInfo.component.isShowing()) { - Rectangle screenBounds = new Rectangle(validationInfo.component.getLocationOnScreen(), validationInfo.component.getSize()); + @NotNull + public static ComponentPopupBuilder createPopupBuilder(@NotNull ValidationInfo info, @Nullable Consumer configurator) { + JEditorPane tipComponent = new JEditorPane(); + View v = BasicHTML.createHTMLView(tipComponent, String.format("%s", info.message)); + String text = v.getPreferredSpan(View.X_AXIS) > MAX_WIDTH.get() ? + String.format("
%s
", MAX_WIDTH.get(), info.message) : + String.format("
%s
", info.message); + + tipComponent.setContentType("text/html"); + tipComponent.setEditable(false); + tipComponent.setEditorKit(UIUtil.getHTMLEditorKit()); + + EditorKit kit = tipComponent.getEditorKit(); + if (kit instanceof HTMLEditorKit) { + StyleSheet css = ((HTMLEditorKit)kit).getStyleSheet(); + + css.addRule("a, a:link {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkColor()) + ";}"); + css.addRule("a:visited {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkVisitedColor()) + ";}"); + css.addRule("a:hover {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkHoverColor()) + ";}"); + css.addRule("a:active {color:#" + ColorUtil.toHex(JBUI.CurrentTheme.Link.linkPressedColor()) + ";}"); + css.addRule("body {background-color:#" + ColorUtil.toHex(info.warning ? warningBackgroundColor() : errorBackgroundColor()) + ";}"); + } + + if (tipComponent.getCaret() instanceof DefaultCaret) { + ((DefaultCaret)tipComponent.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); + } + + tipComponent.setCaretPosition(0); + tipComponent.setText(text); + + tipComponent.setBackground(info.warning ? warningBackgroundColor() : errorBackgroundColor()); + tipComponent.setOpaque(true); + tipComponent.setBorder(getBorder()); + + if (configurator != null) { + configurator.accept(tipComponent); + } + + return JBPopupFactory.getInstance().createComponentPopupBuilder(tipComponent, null). + setBorderColor(info.warning ? warningBorderColor() : errorBorderColor()). + setCancelOnClickOutside(false). + setShowShadow(false). + setCancelOnMouseOutCallback(e -> e.getID() == MouseEvent.MOUSE_PRESSED && !withinComponent(info, e)); + } + + private static boolean withinComponent(@NotNull ValidationInfo info, @NotNull MouseEvent e) { + if (info.component != null && info.component.isShowing()) { + Rectangle screenBounds = new Rectangle(info.component.getLocationOnScreen(), info.component.getSize()); return screenBounds.contains(e.getLocationOnScreen()); } else { diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java new file mode 100644 index 000000000000..861974b98746 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java @@ -0,0 +1,61 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.MouseEvent; + +public abstract class CellComponentProvider { + @NotNull protected final C owner; + + public CellComponentProvider(@NotNull C owner) { + this.owner = owner; + } + + @NotNull + public final C getOwner() { + return owner; + } + + @Nullable + abstract public JComponent getCellRendererComponent(@NotNull Point p); + + @NotNull + abstract public Rectangle getCellRect(@NotNull MouseEvent e); + + /** + * Convenient classes with standard implementations. + */ + public static class TableProvider extends CellComponentProvider { + public TableProvider(@NotNull JTable owner) { + super(owner); + } + + @Nullable + @Override + public JComponent getCellRendererComponent(@NotNull Point p) { + int column = owner.columnAtPoint(p); + int row = owner.rowAtPoint(p); + + if ((column != -1) && (row != -1)) { + TableCellRenderer renderer = owner.getCellRenderer(row, column); + return (JComponent)owner.prepareRenderer(renderer, row, column); + } else { + return null; + } + } + + @NotNull + @Override + public Rectangle getCellRect(@NotNull MouseEvent e) { + Point p = e.getPoint(); + return owner.getCellRect(owner.rowAtPoint(p), owner.columnAtPoint(p), true); + } + } +} + + diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java new file mode 100644 index 000000000000..03f8116fa1af --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -0,0 +1,172 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.popup.ComponentPopupBuilder; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.Alarm; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.HyperlinkListener; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.regex.Pattern; + +public final class CellTooltipManager { + private static final Pattern HTML_A_TAG_PATTERN = Pattern.compile("(?i)]+)>(.+?)"); + + private final Disposable parentDisposable; + + private CellComponentProvider cellComponentProvider; + private HyperlinkListener hyperlinkListener; + + private final Alarm popupAlarm = new Alarm(); + + private ValidationInfo validationInfo; + private boolean closeWithDelay; + + private ComponentPopupBuilder popupBuilder; + private JBPopup cellPopup; + private Dimension popupSize; + private boolean isOverPopup; + private boolean isClosing; + + public CellTooltipManager(@NotNull Disposable parentDisposable) { + this.parentDisposable = parentDisposable; + } + + public CellTooltipManager withCellComponentProvider(@NotNull CellComponentProvider cellComponentProvider) { + this.cellComponentProvider = cellComponentProvider; + return this; + } + + public CellTooltipManager withHyperlinkListener(@NotNull HyperlinkListener hyperlinkListener) { + this.hyperlinkListener = hyperlinkListener; + return this; + } + + public void installOn(@NotNull JComponent component) { + MouseAdapter mouseListener = new ValidationMouseListener(); + + component.addMouseListener(mouseListener); + component.addMouseMotionListener(mouseListener); + + Disposer.register(parentDisposable, () -> { + closePopup(true, null); + + component.removeMouseListener(mouseListener); + component.removeMouseMotionListener(mouseListener); + + cellComponentProvider = null; + validationInfo = null; + popupBuilder = null; + }); + } + + private void handleMouseEvent(MouseEvent e) { + if (cellComponentProvider != null) { + JComponent cellRenderer = cellComponentProvider.getCellRendererComponent(e.getPoint()); + ValidationInfo info = cellRenderer != null ? (ValidationInfo)cellRenderer.getClientProperty(ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY) : null; + + if (info != null) { + if (!info.equals(validationInfo)) { + validationInfo = info; + closeWithDelay = hasATag(validationInfo.message); + + popupBuilder = ComponentValidator.createPopupBuilder(validationInfo, tipComponent -> { + if (closeWithDelay) { + tipComponent.addHyperlinkListener(hyperlinkListener); + tipComponent.addMouseListener(new TipComponentMouseListener()); + } + popupSize = tipComponent.getPreferredSize(); + }); + + closePopup(false, () -> showPopup(e)); + } else if (!isShowing()) { + showPopup(e); + } + } else { + validationInfo = null; + closePopup(false, null); + } + } + } + + private static boolean hasATag(@NotNull String string) { + return HTML_A_TAG_PATTERN.matcher(string).find(); + } + + private void showPopup(MouseEvent e) { + cellPopup = popupBuilder.createPopup(); + + Point cellLocation = cellComponentProvider.getCellRect(e).getLocation(); + Point point = new Point(cellLocation.x + JBUI.scale(40), cellLocation.y - JBUI.scale(6) - popupSize.height); + cellPopup.show(new RelativePoint(cellComponentProvider.getOwner(), point)); + } + + private void closePopup(boolean now, @Nullable Runnable onHidden) { + if (isShowing()) { + if (now || hyperlinkListener == null || !closeWithDelay) { + cellPopup.cancel(); + cellPopup = null; + + if (onHidden != null) { + onHidden.run(); + } + } else if (!isClosing) { + isClosing = true; + popupAlarm.addRequest(() -> { + isClosing = false; + if (!isOverPopup) { + closePopup(true, onHidden); + } + }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + } + } else if (onHidden != null) { + onHidden.run(); + } + } + + private boolean isShowing() { + return cellPopup != null && cellPopup.isVisible(); + } + + private class ValidationMouseListener extends MouseAdapter { + @Override + public void mouseEntered(MouseEvent e) { + handleMouseEvent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + closePopup(false, null); + } + + @Override + public void mouseMoved(MouseEvent e) { + handleMouseEvent(e); + } + } + + private class TipComponentMouseListener extends MouseAdapter { + @Override + public void mouseEntered(MouseEvent e) { + isOverPopup = true; + } + + @Override + public void mouseExited(MouseEvent e) { + isOverPopup = false; + closePopup(true, null); + } + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java new file mode 100644 index 000000000000..fe55357f761d --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -0,0 +1,72 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.ui.CellRendererPanel; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ValidatingTableCellRendererWrapper extends CellRendererPanel implements TableCellRenderer { + public static final String CELL_VALIDATION_PROPERTY = "CellRenderer.validationInfo"; + + private final TableCellRenderer delegate; + private final JLabel iconLabel = new JLabel(); + + private Supplier editorSizeSupplier = () -> JBUI.emptySize(); + private Function cellValidator; + + public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { + this.delegate = delegate; + setLayout(new BorderLayout(0, 0)); + add(iconLabel, BorderLayout.EAST); + + iconLabel.setOpaque(false); + iconLabel.setBorder(JBUI.Borders.emptyRight(6)); + setOpaque(true); + setName("Table.cellRenderer"); + } + + public ValidatingTableCellRendererWrapper bindToEditorSize(@NotNull Supplier editorSizeSupplier) { + this.editorSizeSupplier = editorSizeSupplier; + return this; + } + + public ValidatingTableCellRendererWrapper withCellValidator(@NotNull Function cellValidator) { + this.cellValidator = cellValidator; + return this; + } + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = Math.max(size.height, editorSizeSupplier.get().height); + return size; + } + + @Override + public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JComponent delegateRenderer = (JComponent)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + if (cellValidator != null) { + ValidationInfo result = cellValidator.apply(value); + iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); + putClientProperty(CELL_VALIDATION_PROPERTY, result); + } + + add(delegateRenderer, BorderLayout.CENTER); + setBorder(delegateRenderer.getBorder()); + delegateRenderer.setBorder(null); + + setBackground(delegateRenderer.getBackground()); + + setSelected(isSelected); + return this; + } +} diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index 659190f1cd9c..9c18bcce0404 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -10,6 +10,9 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.*; +import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; +import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; +import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; import com.intellij.openapi.ui.panel.ComponentPanel; import com.intellij.openapi.ui.panel.ProgressPanel; import com.intellij.openapi.util.text.StringUtil; @@ -36,7 +39,6 @@ import javax.swing.event.HyperlinkEvent; import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import java.awt.*; import java.net.MalformedURLException; @@ -87,6 +89,9 @@ public class ComponentPanelTestAction extends DumbAwareAction { private static final String[] STRING_VALUES = { "One", "Two", "Three", "Four", "Five", "Six" }; private static final SimpleTextAttributes WARNING_CELL_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_WAVED, null); + private static final ValidationInfo NULL_VALUE_ERROR = new ValidationInfo("Null value"); + private static final ValidationInfo NAN_VALUE_ERROR = new ValidationInfo("Not a number"); + private final Alarm myAlarm = new Alarm(getDisposable()); private ProgressTimerRequest progressTimerRequest; @@ -249,6 +254,18 @@ public class ComponentPanelTestAction extends DumbAwareAction { topPanel.add(UI.PanelFactory.panel(new JComboBox<>(STRING_VALUES)). withComment("Combobox comment").createPanel(), gc); + JBScrollPane pane = new JBScrollPane(createTable()); + pane.setPreferredSize(JBUI.size(400, 300)); + pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL); + + BorderLayoutPanel mainPanel = JBUI.Panels.simplePanel(UI.PanelFactory.panel(pane). + withLabel("Table label:").moveLabelOnTop().withComment("Table comment").resizeY(true).createPanel()); + mainPanel.addToTop(topPanel); + + return mainPanel; + } + + private JComponent createTable() { String[] columns = { "First column", "Second column" }; String[][] data = {{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}, {"seven", "7"}, {"eight", "8"}, {"nine", "9"}, {"ten", "10"}, {"eleven", "11"}, @@ -274,6 +291,16 @@ public class ComponentPanelTestAction extends DumbAwareAction { } }); + // Install custom tooltip manager for displaying error/warning tooltips + new CellTooltipManager(getDisposable()). + withCellComponentProvider(new CellComponentProvider.TableProvider(table)). + withHyperlinkListener(e -> { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + System.out.println("Table cell tooltip link clicked. Desc = " + e.getDescription()); + } + }).installOn(table); + + // Configure left column ExtendableTextField cellEditor = new ExtendableTextField(); ExtendableTextComponent.Extension browseExtension = ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, @@ -300,12 +327,13 @@ public class ComponentPanelTestAction extends DumbAwareAction { TableColumn col = table.getColumnModel().getColumn(0); col.setCellEditor(new DefaultCellEditor(cellEditor)); col.setCellRenderer(new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). - bindToEditor(cellEditor). - withCellValidator((value, row, column) -> value == null ? ValidationResult.ERROR : - ALLOWED_VALUES.contains(value.toString()) ? - ValidationResult.OK : - ValidationResult.asError("Illegal value: " + value.toString()))); + bindToEditorSize(cellEditor::getPreferredSize). + withCellValidator(value -> + value == null ? new ValidationInfo("Null value") : + ALLOWED_VALUES.contains(value.toString()) ? null : + new ValidationInfo("Illegal value: " + value.toString() + "
Please check rules."))); + // Configure right column JComboBox rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); col = table.getColumnModel().getColumn(1); @@ -330,51 +358,21 @@ public class ComponentPanelTestAction extends DumbAwareAction { } } } - }).bindToEditor(rightEditor). - withCellValidator((value, row, column) -> { - if (value == null) return ValidationResult.ERROR; + }). + bindToEditorSize(rightEditor::getPreferredSize). + withCellValidator(value -> { + if (value == null) return NULL_VALUE_ERROR; else { try { int iv = Integer.parseInt(value.toString()); - return iv <= 8 ? ValidationResult.OK : ValidationResult.asWarning("Value " + value.toString() + " is not preferred"); + return iv <= 8 ? null : new ValidationInfo("Value " + value.toString() + " is not preferred").asWarning(); } catch (NumberFormatException nfe) { - return ValidationResult.ERROR; + return NAN_VALUE_ERROR; } } })); - //col.setCellRenderer(new ColoredTableCellRenderer() { - // { - // setIpad(JBUI.emptyInsets()); - // } - // - // @Override - // protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, - // boolean hasFocus, int row, int column) { - // if (value == null) { - // append("No data", SimpleTextAttributes.ERROR_ATTRIBUTES); - // } - // else { - // try { - // int iv = Integer.parseInt(value.toString()); - // append("value ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES); - // append(value.toString(), iv % 2 == 1 ? SimpleTextAttributes.REGULAR_ATTRIBUTES : WARNING_CELL_ATTRIBUTES); - // } catch (NumberFormatException nfe) { - // append(value.toString(), SimpleTextAttributes.ERROR_ATTRIBUTES); - // } - // } - // } - //}); - - JBScrollPane pane = new JBScrollPane(table); - pane.setPreferredSize(JBUI.size(400, 300)); - pane.putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.ALL); - - BorderLayoutPanel mainPanel = JBUI.Panels.simplePanel(UI.PanelFactory.panel(pane). - withLabel("Table label:").moveLabelOnTop().withComment("Table comment").resizeY(true).createPanel()); - mainPanel.addToTop(topPanel); - - return mainPanel; + return table; } private JComponent createComponentGridPanel() { @@ -669,115 +667,5 @@ public class ComponentPanelTestAction extends DumbAwareAction { return JBUI.Panels.simplePanel().addToTop(panel); } - - public static class ValidationResult { - public static final ValidationResult OK = new ValidationResult(State.Ok, null); - public static final ValidationResult ERROR = new ValidationResult(State.Error, null); - public static final ValidationResult WARNING = new ValidationResult(State.Warning, null); - - public static ValidationResult asError(@NotNull String tooltip) { - return new ValidationResult(State.Error, tooltip); - } - - public static ValidationResult asWarning(@NotNull String tooltip) { - return new ValidationResult(State.Warning, tooltip); - } - - public enum State { - Ok, Warning, Error - } - - @NotNull private final State state; - @Nullable private final String tooltip; - - private ValidationResult(@NotNull State state, @Nullable String tooltip) { - this.state = state; - this.tooltip = tooltip; - } - - @NotNull - public State getState() { - return state; - } - - @Nullable - public String getTooltipText() { - return tooltip; - } - } - - public interface CellValidator { - ValidationResult apply(@Nullable Object value, int row, int col); - } - - public static class ValidatingTableCellRendererWrapper extends CellRendererPanel implements TableCellRenderer { - private final TableCellRenderer delegate; - private final JLabel iconLabel = new JLabel(); - - private JComponent cellEditor; - private CellValidator cellValidator; - - public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { - this.delegate = delegate; - setLayout(new BorderLayout(0, 0)); - add(iconLabel, BorderLayout.EAST); - - iconLabel.setOpaque(false); - iconLabel.setBorder(JBUI.Borders.emptyRight(6)); - setOpaque(true); - setName("Table.cellRenderer"); - } - - public ValidatingTableCellRendererWrapper bindToEditor(@NotNull JComponent cellEditor) { - this.cellEditor = cellEditor; - return this; - } - - public ValidatingTableCellRendererWrapper withCellValidator(CellValidator cellValidator) { - this.cellValidator = cellValidator; - return this; - } - - @Override - public Dimension getPreferredSize() { - Dimension size = super.getPreferredSize(); - if (cellEditor != null) { - Dimension editorSize = cellEditor.getPreferredSize(); - size.height = Math.max(size.height, editorSize.height); - } - - return size; - } - - @Override - public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (cellValidator != null) { - ValidationResult result = cellValidator.apply(value, row, column); - switch (result.getState()) { - case Ok: - iconLabel.setIcon(null); - break; - case Error: - iconLabel.setIcon(AllIcons.General.BalloonError); - break; - case Warning: - iconLabel.setIcon(AllIcons.General.BalloonWarning); - break; - } - setToolTipText(result.getTooltipText()); - } - - JComponent delegateRenderer = (JComponent)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - add(delegateRenderer, BorderLayout.CENTER); - setBorder(delegateRenderer.getBorder()); - delegateRenderer.setBorder(null); - - setBackground(delegateRenderer.getBackground()); - - setSelected(isSelected); - return this; - } - } } } From 2e80fceaa9e13b45ced7cca0a2fd7dd01d906597 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Mon, 28 Jan 2019 13:52:31 +0300 Subject: [PATCH 025/138] IDEA-205679 Added cellEditor tooltips and document listener to ComponentValidator. --- .../openapi/ui/ComponentValidator.java | 40 +++++++--- .../cellvalidators/CellComponentProvider.java | 8 +- .../ui/cellvalidators/CellTooltipManager.java | 14 ++-- .../internal/ui/ComponentPanelTestAction.java | 77 ++++++++----------- 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java b/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java index 244a70247b88..d1adcf2d43f4 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComponentValidator.java @@ -9,6 +9,7 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ColorUtil; +import com.intellij.ui.DocumentAdapter; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; import com.intellij.util.ui.JBEmptyBorder; @@ -20,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; import javax.swing.event.HyperlinkListener; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.DefaultCaret; @@ -157,6 +159,19 @@ public class ComponentValidator { return this; } + /** + * Convenient wrapper for mostly used scenario. + */ + public ComponentValidator andRegisterOnDocumentListener(@NotNull JTextComponent textComponent) { + textComponent.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(@NotNull DocumentEvent e) { + getInstance(textComponent).ifPresent(ComponentValidator::revalidate); // Don't use 'this' to avoid cyclic references. + } + }); + return this; + } + public void revalidate() { if (validator != null) { updateInfo(validator.get()); @@ -175,7 +190,7 @@ public class ComponentValidator { validationInfo.component.repaint(); } - hidePopup(); + hidePopup(true); popupBuilder = null; popupLocation = null; @@ -288,15 +303,18 @@ public class ComponentValidator { } } - private void hidePopup() { + private void hidePopup(boolean now) { if (popup != null && popup.isVisible()) { - popupAlarm.cancelAllRequests(); - popupAlarm.addRequest(() -> { - if (popup != null && (!isOverPopup || hyperlinkListener == null)) { - popup.cancel(); - popup = null; - } - }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + if (now || hyperlinkListener == null) { + popup.cancel(); + popup = null; + } else { + popupAlarm.addRequest(() -> { + if (!isOverPopup || hyperlinkListener == null) { + hidePopup(true); + } + }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); + } } } @@ -319,7 +337,7 @@ public class ComponentValidator { @Override public void focusLost(FocusEvent e) { - hidePopup(); + hidePopup(false); ValidationInfo info = null; if (focusValidator != null) { @@ -346,7 +364,7 @@ public class ComponentValidator { if (validationInfo != null) { getFocusable(validationInfo.component).ifPresent(fc -> { if (!fc.hasFocus()) { - hidePopup(); + hidePopup(false); } }); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java index 861974b98746..a82084e85bd2 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java @@ -27,11 +27,15 @@ public abstract class CellComponentProvider { @NotNull abstract public Rectangle getCellRect(@NotNull MouseEvent e); + public static CellComponentProvider forTable(JTable table) { + return new TableProvider(table); + } + /** * Convenient classes with standard implementations. */ - public static class TableProvider extends CellComponentProvider { - public TableProvider(@NotNull JTable owner) { + private static class TableProvider extends CellComponentProvider { + private TableProvider(@NotNull JTable owner) { super(owner); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java index 03f8116fa1af..1018c3905c60 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -61,7 +61,7 @@ public final class CellTooltipManager { component.addMouseMotionListener(mouseListener); Disposer.register(parentDisposable, () -> { - closePopup(true, null); + hidePopup(true, null); component.removeMouseListener(mouseListener); component.removeMouseMotionListener(mouseListener); @@ -90,13 +90,13 @@ public final class CellTooltipManager { popupSize = tipComponent.getPreferredSize(); }); - closePopup(false, () -> showPopup(e)); + hidePopup(false, () -> showPopup(e)); } else if (!isShowing()) { showPopup(e); } } else { validationInfo = null; - closePopup(false, null); + hidePopup(false, null); } } } @@ -113,7 +113,7 @@ public final class CellTooltipManager { cellPopup.show(new RelativePoint(cellComponentProvider.getOwner(), point)); } - private void closePopup(boolean now, @Nullable Runnable onHidden) { + private void hidePopup(boolean now, @Nullable Runnable onHidden) { if (isShowing()) { if (now || hyperlinkListener == null || !closeWithDelay) { cellPopup.cancel(); @@ -127,7 +127,7 @@ public final class CellTooltipManager { popupAlarm.addRequest(() -> { isClosing = false; if (!isOverPopup) { - closePopup(true, onHidden); + hidePopup(true, onHidden); } }, Registry.intValue("ide.tooltip.initialDelay.highlighter")); } @@ -148,7 +148,7 @@ public final class CellTooltipManager { @Override public void mouseExited(MouseEvent e) { - closePopup(false, null); + hidePopup(false, null); } @Override @@ -166,7 +166,7 @@ public final class CellTooltipManager { @Override public void mouseExited(MouseEvent e) { isOverPopup = false; - closePopup(true, null); + hidePopup(true, null); } } } diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index 9c18bcce0404..738bfdb2476c 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -13,7 +13,6 @@ import com.intellij.openapi.ui.*; import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; -import com.intellij.openapi.ui.panel.ComponentPanel; import com.intellij.openapi.ui.panel.ProgressPanel; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; @@ -36,6 +35,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; @@ -45,6 +45,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.HashSet; +import java.util.function.BiFunction; public class ComponentPanelTestAction extends DumbAwareAction { private enum Placement { @@ -188,7 +189,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { } else { return null; } - }).installOn(text1); + }).andRegisterOnDocumentListener(text1).installOn(text1); Dimension d = text1.getPreferredSize(); text1.setPreferredSize(new Dimension(JBUI.scale(100), d.height)); @@ -208,31 +209,11 @@ public class ComponentPanelTestAction extends DumbAwareAction { String tt = text2.getText(); return StringUtil.isEmpty(tt) || tt.length() < 5 ? new ValidationInfo("Message is too short.
Should contain at least 5 symbols.
Please check rules.", text2) : null; - }).andStartOnFocusLost().installOn(text2); + }).andStartOnFocusLost().andRegisterOnDocumentListener(text2).installOn(text2); gc.gridy++; topPanel.add(UI.PanelFactory.panel(text2).withLabel("&Path:").createPanel(), gc); - ComponentPanel cp = ComponentPanel.getComponentPanel(text2); - text1.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - String text = text1.getText(); - if (cp != null) { - cp.setCommentText(text); - } - - ComponentValidator.getInstance(text1).ifPresent(ComponentValidator::revalidate); - } - }); - - text2.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - ComponentValidator.getInstance(text2).ifPresent(ComponentValidator::revalidate); - } - }); - JCheckBox cb1 = new JCheckBox("Scroll tab layout"); cb1.addActionListener(e -> pane.setTabLayoutPolicy(cb1.isSelected() ? JTabbedPane.SCROLL_TAB_LAYOUT : JTabbedPane.WRAP_TAB_LAYOUT)); gc.gridy++; @@ -291,14 +272,20 @@ public class ComponentPanelTestAction extends DumbAwareAction { } }); + HyperlinkListener hyperlinkListener = e -> { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + System.out.println("Table cell tooltip link clicked. Desc = " + e.getDescription()); + } + }; + + BiFunction validationInfoGenerator = (text, component) -> + new ValidationInfo("Illegal value: " + text + "
Please check rules.", component); + // Install custom tooltip manager for displaying error/warning tooltips new CellTooltipManager(getDisposable()). - withCellComponentProvider(new CellComponentProvider.TableProvider(table)). - withHyperlinkListener(e -> { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - System.out.println("Table cell tooltip link clicked. Desc = " + e.getDescription()); - } - }).installOn(table); + //withCellComponentProvider(CellComponentProvider.forTable(table)). + withCellComponentProvider(CellComponentProvider.forTable(table)). + withHyperlinkListener(hyperlinkListener).installOn(table); // Configure left column ExtendableTextField cellEditor = new ExtendableTextField(); @@ -306,23 +293,24 @@ public class ComponentPanelTestAction extends DumbAwareAction { ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, "Open file", () -> System.out.println("Table browse clicked")); ExtendableTextComponent.Extension errorExtension = - ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, "Value not allowed", () -> System.out.println("Error clicked")); + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, null, null); cellEditor.addExtension(browseExtension); cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); - cellEditor.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - if (ALLOWED_VALUES.contains(cellEditor.getText())) { - cellEditor.putClientProperty("JComponent.outline", null); - cellEditor.removeExtension(errorExtension); - } - else if (cellEditor.getClientProperty("JComponent.outline") == null) { - cellEditor.putClientProperty("JComponent.outline", "error"); - cellEditor.addExtension(errorExtension); - } + + new ComponentValidator(getDisposable()).withValidator(() -> { + boolean isAllowed = ALLOWED_VALUES.contains(cellEditor.getText()); + if (isAllowed) { + cellEditor.removeExtension(errorExtension); } - }); + else if (cellEditor.getClientProperty("JComponent.outline") == null) { + cellEditor.addExtension(errorExtension); + } + + return isAllowed ? null : validationInfoGenerator.apply(cellEditor.getText(), cellEditor); + }).withHyperlinkListener(hyperlinkListener). + andRegisterOnDocumentListener(cellEditor). + installOn(cellEditor); TableColumn col = table.getColumnModel().getColumn(0); col.setCellEditor(new DefaultCellEditor(cellEditor)); @@ -331,7 +319,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { withCellValidator(value -> value == null ? new ValidationInfo("Null value") : ALLOWED_VALUES.contains(value.toString()) ? null : - new ValidationInfo("Illegal value: " + value.toString() + "
Please check rules."))); + validationInfoGenerator.apply(value.toString(), null))); // Configure right column JComboBox rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); @@ -358,8 +346,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { } } } - }). - bindToEditorSize(rightEditor::getPreferredSize). + }).bindToEditorSize(rightEditor::getPreferredSize). withCellValidator(value -> { if (value == null) return NULL_VALUE_ERROR; else { From c33d82d32890c02aede7f5701e4fed49eedb80e7 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Wed, 30 Jan 2019 14:36:37 +0300 Subject: [PATCH 026/138] IDEA-205679 Use new table validation in the plugin repositories table --- .../cellvalidators/CellComponentProvider.java | 8 +- .../ui/cellvalidators/CellTooltipManager.java | 12 +- .../ui/cellvalidators/TableCellValidator.java | 8 + .../ValidatingTableCellRendererWrapper.java | 7 +- .../ide/plugins/PluginHostsConfigurable.java | 154 +++++------------- .../internal/ui/ComponentPanelTestAction.java | 5 +- 6 files changed, 73 insertions(+), 121 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java index a82084e85bd2..5f87d6cbc6d7 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java @@ -32,10 +32,12 @@ public abstract class CellComponentProvider { } /** - * Convenient classes with standard implementations. + * Convenient classes with standard implementations. Don't use the class directly. + * It can either be created with {@link CellComponentProvider#forTable(JTable)} method or + * be extended. */ - private static class TableProvider extends CellComponentProvider { - private TableProvider(@NotNull JTable owner) { + public static class TableProvider extends CellComponentProvider { + protected TableProvider(@NotNull JTable owner) { super(owner); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java index 1018c3905c60..f94ffe389835 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -36,6 +36,7 @@ public final class CellTooltipManager { private ComponentPopupBuilder popupBuilder; private JBPopup cellPopup; + private Point cellLocation; private Dimension popupSize; private boolean isOverPopup; private boolean isClosing; @@ -93,6 +94,14 @@ public final class CellTooltipManager { hidePopup(false, () -> showPopup(e)); } else if (!isShowing()) { showPopup(e); + } else { // Move popup to new location + Point location = cellComponentProvider.getCellRect(e).getLocation(); + if (!location.equals(cellLocation)) { + cellLocation = location; + Point point = new Point(cellLocation.x + JBUI.scale(40), cellLocation.y - JBUI.scale(6) - popupSize.height); + SwingUtilities.convertPointToScreen(point, cellComponentProvider.getOwner()); + cellPopup.setLocation(point); + } } } else { validationInfo = null; @@ -107,8 +116,7 @@ public final class CellTooltipManager { private void showPopup(MouseEvent e) { cellPopup = popupBuilder.createPopup(); - - Point cellLocation = cellComponentProvider.getCellRect(e).getLocation(); + cellLocation = cellComponentProvider.getCellRect(e).getLocation(); Point point = new Point(cellLocation.x + JBUI.scale(40), cellLocation.y - JBUI.scale(6) - popupSize.height); cellPopup.show(new RelativePoint(cellComponentProvider.getOwner(), point)); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java new file mode 100644 index 000000000000..0c10da752e04 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java @@ -0,0 +1,8 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import com.intellij.openapi.ui.ValidationInfo; + +public interface TableCellValidator { + ValidationInfo validate(Object value, int row, int column); +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java index fe55357f761d..e56c395cd82a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.table.TableCellRenderer; import java.awt.*; -import java.util.function.Function; import java.util.function.Supplier; public class ValidatingTableCellRendererWrapper extends CellRendererPanel implements TableCellRenderer { @@ -20,7 +19,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem private final JLabel iconLabel = new JLabel(); private Supplier editorSizeSupplier = () -> JBUI.emptySize(); - private Function cellValidator; + private TableCellValidator cellValidator; public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { this.delegate = delegate; @@ -38,7 +37,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem return this; } - public ValidatingTableCellRendererWrapper withCellValidator(@NotNull Function cellValidator) { + public ValidatingTableCellRendererWrapper withCellValidator(@NotNull TableCellValidator cellValidator) { this.cellValidator = cellValidator; return this; } @@ -55,7 +54,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem JComponent delegateRenderer = (JComponent)delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (cellValidator != null) { - ValidationInfo result = cellValidator.apply(value); + ValidationInfo result = cellValidator.validate(value, row, column); iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); putClientProperty(CELL_VALIDATION_PROPERTY, result); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index cf68206f1655..91280ac8bfac 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -2,6 +2,8 @@ package com.intellij.ide.plugins; import com.intellij.ide.IdeBundle; +import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.options.Configurable; @@ -9,11 +11,12 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.intellij.openapi.ui.ComponentValidator; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; +import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; +import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; import com.intellij.openapi.updateSettings.impl.UpdateSettings; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.ui.AnimatedIcon; @@ -33,8 +36,6 @@ import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -48,6 +49,7 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura }; private final AnimatedIcon.Default myAnimatedIcon = new AnimatedIcon.Default(); + private final Disposable myDisposable = Disposer.newDisposable(); private final JBTable myTable = new JBTable(myModel) { @Override @@ -135,119 +137,53 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - myTable.setDefaultRenderer(Object.class, new ColoredTableCellRenderer() { - final SimpleTextAttributes ERROR_ATTRIBUTES = - new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, DialogWrapper.ERROR_FOREGROUND_COLOR); + JTextField cellEditor = new JTextField(); + cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); - @Override - protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { - if (row >= 0 && row < myModel.getRowCount()) { - UrlInfo info = myModel.getRowValue(row); - setBorder(null); - setForeground(selected ? table.getSelectionForeground() : table.getForeground()); - setBackground(selected ? table.getSelectionBackground() : table.getBackground()); - append(info.name, info.errorTooltip != null && !info.progress ? ERROR_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); - } - } - - @Override - protected SimpleTextAttributes modifyAttributes(SimpleTextAttributes attributes) { - return attributes; - } - }); - - DefaultCellEditor editor = new DefaultCellEditor(new JTextField()); + DefaultCellEditor editor = new DefaultCellEditor(cellEditor); editor.setClickCountToStart(1); myTable.setDefaultEditor(Object.class, editor); - createValidatorHandler(); + myTable.setDefaultRenderer(Object.class, new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { + { setIpad(JBUI.emptyInsets());} + + @Override + protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { + if (row >= 0 && row < myModel.getRowCount()) { + UrlInfo info = myModel.getRowValue(row); + setBorder(null); + setForeground(selected ? table.getSelectionForeground() : table.getForeground()); + setBackground(selected ? table.getSelectionBackground() : table.getBackground()); + append(info.name, SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + } + + @Override + protected SimpleTextAttributes modifyAttributes(SimpleTextAttributes attributes) { + return attributes; + } + }). + bindToEditorSize(cellEditor::getPreferredSize). + withCellValidator((value, row, column) -> { + if (row >= 0 && row < myModel.getRowCount()) { + UrlInfo info = myModel.getRowValue(row); + return info.errorTooltip == null || info.progress ? null : new ValidationInfo(info.errorTooltip); + } + else { + return null; + } + })); + + new CellTooltipManager(myDisposable). + withCellComponentProvider(CellComponentProvider.forTable(myTable)). + installOn(myTable); return ToolbarDecorator.createDecorator(myTable).disableUpDownActions().createPanel(); } - private void createValidatorHandler() { - MouseAdapter listener = new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - showErrorPopup(e); - } - - @Override - public void mouseExited(MouseEvent event) { - if (!myTable.contains(event.getX(), event.getY()) || myTable.rowAtPoint(event.getPoint()) == myTable.getEditingRow()) { - hideErrorPopup(); - } - } - - @Override - public void mouseMoved(MouseEvent e) { - showErrorPopup(e); - } - }; - myTable.addMouseListener(listener); - myTable.addMouseMotionListener(listener); - } - - private JBPopup myErrorPopup; - private JLabel myErrorLabel; - - private void showErrorPopup(@NotNull MouseEvent event) { - int row = myTable.rowAtPoint(event.getPoint()); - if (row == -1 || row == myTable.getEditingRow()) { - hideErrorPopup(); - return; - } - - UrlInfo item = myModel.getItem(row); - if (item.progress || item.errorTooltip == null) { - hideErrorPopup(); - return; - } - - if (myErrorPopup != null && myErrorPopup.isVisible() && myErrorPopup.getContent().getParent() != null) { - myErrorLabel.setText(item.errorTooltip); - showErrorPopup(row, true); - return; - } - - hideErrorPopup(); - - myErrorLabel = new JLabel(item.errorTooltip); - myErrorLabel.setOpaque(true); - myErrorLabel.setBackground(JBUI.CurrentTheme.Validator.errorBackgroundColor()); - myErrorLabel.setBorder(ComponentValidator.getBorder()); - - myErrorPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myErrorLabel, null) - .setBorderColor(JBUI.CurrentTheme.Validator.errorBorderColor()).setShowShadow(false).createPopup(); - - showErrorPopup(row, false); - } - - private void showErrorPopup(int row, boolean update) { - Rectangle cellRect = myTable.getCellRect(row, 0, false); - Point location = new Point(cellRect.x + JBUI.scale(40), cellRect.y - myErrorLabel.getPreferredSize().height - JBUI.scale(4)); - SwingUtilities.convertPointToScreen(location, myTable); - - if (update) { - myErrorPopup.pack(true, true); - myErrorPopup.setLocation(location); - } - else { - myErrorPopup.showInScreenCoordinates(myTable, location); - } - } - @Override public void disposeUIResources() { - hideErrorPopup(); - } - - private void hideErrorPopup() { - if (myErrorPopup != null) { - myErrorPopup.cancel(); - myErrorPopup = null; - myErrorLabel = null; - } + Disposer.dispose(myDisposable); } private void validateRepositories(@NotNull List urls) { diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index 738bfdb2476c..3318c67af72d 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -283,7 +283,6 @@ public class ComponentPanelTestAction extends DumbAwareAction { // Install custom tooltip manager for displaying error/warning tooltips new CellTooltipManager(getDisposable()). - //withCellComponentProvider(CellComponentProvider.forTable(table)). withCellComponentProvider(CellComponentProvider.forTable(table)). withHyperlinkListener(hyperlinkListener).installOn(table); @@ -316,7 +315,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { col.setCellEditor(new DefaultCellEditor(cellEditor)); col.setCellRenderer(new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). bindToEditorSize(cellEditor::getPreferredSize). - withCellValidator(value -> + withCellValidator((value, row, column) -> value == null ? new ValidationInfo("Null value") : ALLOWED_VALUES.contains(value.toString()) ? null : validationInfoGenerator.apply(value.toString(), null))); @@ -347,7 +346,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { } } }).bindToEditorSize(rightEditor::getPreferredSize). - withCellValidator(value -> { + withCellValidator((value, row, column) -> { if (value == null) return NULL_VALUE_ERROR; else { try { From de0906bd35143de7100564040b3d5073f80b4e20 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Thu, 31 Jan 2019 13:44:33 +0300 Subject: [PATCH 027/138] IDEA-205679 Plugin host table stateful cell editor validation added --- .../ui/cellvalidators/CellTooltipManager.java | 6 +- .../ValidatingTableCellRendererWrapper.java | 11 ++- .../ui/cellvalidators/ValidationUtils.java | 86 +++++++++++++++++++ .../ide/plugins/PluginHostsConfigurable.java | 10 +-- .../internal/ui/ComponentPanelTestAction.java | 11 +-- 5 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java index f94ffe389835..be0932014c07 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -92,9 +92,11 @@ public final class CellTooltipManager { }); hidePopup(false, () -> showPopup(e)); - } else if (!isShowing()) { + } + else if (!isShowing()) { showPopup(e); - } else { // Move popup to new location + } + else if (!isClosing) { // Move popup to new location Point location = cellComponentProvider.getCellRect(e).getLocation(); if (!location.equals(cellLocation)) { cellLocation = location; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java index e56c395cd82a..98c9d7808bcc 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -27,8 +27,6 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem add(iconLabel, BorderLayout.EAST); iconLabel.setOpaque(false); - iconLabel.setBorder(JBUI.Borders.emptyRight(6)); - setOpaque(true); setName("Table.cellRenderer"); } @@ -56,6 +54,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem if (cellValidator != null) { ValidationInfo result = cellValidator.validate(value, row, column); iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); + iconLabel.setBorder(result == null ? null: JBUI.Borders.emptyRight(4)); putClientProperty(CELL_VALIDATION_PROPERTY, result); } @@ -64,8 +63,12 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem delegateRenderer.setBorder(null); setBackground(delegateRenderer.getBackground()); - - setSelected(isSelected); return this; } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java new file mode 100644 index 000000000000..4730b43fc7d5 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java @@ -0,0 +1,86 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.components.fields.ExtendableTextComponent; +import com.intellij.ui.components.fields.ExtendableTextField; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; + +import static com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY; + +public final class ValidationUtils { + private ValidationUtils() {} + + public final static ExtendableTextComponent.Extension ERROR_EXTENSION = + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, null, null); + + public static void setErrorExtension(ExtendableTextComponent editor, boolean set) { + if (!set) { + editor.removeExtension(ERROR_EXTENSION); + } else if (editor instanceof JComponent && ((JComponent)editor).getClientProperty("JComponent.outline") == null) { + editor.addExtension(ERROR_EXTENSION); + } + } + + public static class StatefulValidatingEditor extends DefaultCellEditor { + public StatefulValidatingEditor(Disposable disposable) { + super(new ExtendableTextField()); + editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); + + ExtendableTextField extendableTextField = (ExtendableTextField)editorComponent; + + new ComponentValidator(disposable).withValidator(() -> { + ValidationInfo info = (ValidationInfo)extendableTextField.getClientProperty(CELL_VALIDATION_PROPERTY); + setErrorExtension(extendableTextField, info != null); + return info; + }).installOn(extendableTextField); + + DocumentListener dl = new DocumentAdapter() { + @Override + protected void textChanged(@NotNull DocumentEvent e) { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + } + }; + + extendableTextField.getDocument().addDocumentListener(dl); + Disposer.register(disposable, () -> extendableTextField.getDocument().removeDocumentListener(dl)); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + JComponent editor = (JComponent)super.getTableCellEditorComponent(table, value, isSelected, row, column); + JComponent renderer = (JComponent)table.getCellRenderer(row, column).getTableCellRendererComponent(table, value, isSelected, true, row, column); + ValidationInfo cellInfo = renderer != null ? (ValidationInfo)renderer.getClientProperty(CELL_VALIDATION_PROPERTY) : null; + if (cellInfo != null) { + editor.putClientProperty(CELL_VALIDATION_PROPERTY, new ValidationInfo(cellInfo.message, editor)); + ComponentValidator.getInstance(editor).ifPresent(ComponentValidator::revalidate); + } + return editor; + } + + @Override + public boolean stopCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + return super.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + super.cancelCellEditing(); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index 91280ac8bfac..39656adfc8fd 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -2,7 +2,6 @@ package com.intellij.ide.plugins; import com.intellij.ide.IdeBundle; -import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -40,6 +39,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static com.intellij.openapi.ui.cellvalidators.ValidationUtils.StatefulValidatingEditor; + public class PluginHostsConfigurable implements Configurable.NoScroll, Configurable { private final ListTableModel myModel = new ListTableModel() { @Override @@ -137,10 +138,7 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - JTextField cellEditor = new JTextField(); - cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); - - DefaultCellEditor editor = new DefaultCellEditor(cellEditor); + DefaultCellEditor editor = new StatefulValidatingEditor(myDisposable); editor.setClickCountToStart(1); myTable.setDefaultEditor(Object.class, editor); @@ -163,7 +161,7 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura return attributes; } }). - bindToEditorSize(cellEditor::getPreferredSize). + bindToEditorSize(editor.getComponent()::getPreferredSize). withCellValidator((value, row, column) -> { if (row >= 0 && row < myModel.getRowCount()) { UrlInfo info = myModel.getRowValue(row); diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index 3318c67af72d..2b05680e3310 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -13,6 +13,7 @@ import com.intellij.openapi.ui.*; import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; +import com.intellij.openapi.ui.cellvalidators.ValidationUtils; import com.intellij.openapi.ui.panel.ProgressPanel; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; @@ -291,21 +292,13 @@ public class ComponentPanelTestAction extends DumbAwareAction { ExtendableTextComponent.Extension browseExtension = ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, "Open file", () -> System.out.println("Table browse clicked")); - ExtendableTextComponent.Extension errorExtension = - ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, null, null); cellEditor.addExtension(browseExtension); cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); new ComponentValidator(getDisposable()).withValidator(() -> { boolean isAllowed = ALLOWED_VALUES.contains(cellEditor.getText()); - if (isAllowed) { - cellEditor.removeExtension(errorExtension); - } - else if (cellEditor.getClientProperty("JComponent.outline") == null) { - cellEditor.addExtension(errorExtension); - } - + ValidationUtils.setErrorExtension(cellEditor, !isAllowed); return isAllowed ? null : validationInfoGenerator.apply(cellEditor.getText(), cellEditor); }).withHyperlinkListener(hyperlinkListener). andRegisterOnDocumentListener(cellEditor). From a5a1c1660b4d1e27364e0e01f7df833c6fae40b1 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Thu, 31 Jan 2019 16:55:02 +0300 Subject: [PATCH 028/138] IDEA-205679 Implement validation in ExcludeTable --- .../options/editor/ExcludeTable.java | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java index 4812b37cdd6c..6f525bb0c0aa 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java +++ b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java @@ -5,14 +5,23 @@ import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.JavaProjectCodeInsightSettings; import com.intellij.execution.util.ListTableWithButtons; import com.intellij.icons.AllIcons; +import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBoxTableRenderer; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; +import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; +import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; +import com.intellij.openapi.ui.cellvalidators.ValidationUtils; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.ui.DocumentAdapter; -import com.intellij.ui.GuiUtils; -import com.intellij.ui.JBColor; import com.intellij.ui.ScrollingUtil; +import com.intellij.ui.components.fields.ExtendableTextField; +import com.intellij.ui.table.JBTable; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColumnInfo; @@ -22,20 +31,26 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.DocumentEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; -import java.awt.*; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.function.BiFunction; import java.util.regex.Pattern; class ExcludeTable extends ListTableWithButtons { private static final Pattern ourPackagePattern = Pattern.compile("([\\w*]+\\.)*[\\w*]+"); + + private static final BiFunction validationInfoProducer = (value, component) -> + (value == null || StringUtil.isEmpty(value.toString()) || ourPackagePattern.matcher(value.toString()).matches()) ? + null : new ValidationInfo("Illegal name: " + value.toString(), component); + + private static final Disposable validatorsDisposable = Disposer.newDisposable(); private static final ColumnInfo NAME_COLUMN = new ColumnInfo("Class/package/member qualified name mask") { + @Nullable @Override public String valueOf(Item pair) { @@ -44,35 +59,24 @@ class ExcludeTable extends ListTableWithButtons { @Override public TableCellEditor getEditor(Item pair) { - final JTextField field = GuiUtils.createUndoableTextField(); - field.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - field.putClientProperty("JComponent.outline", - ourPackagePattern.matcher(field.getText()).matches() ? null : "error"); - } - }); - return new DefaultCellEditor(field); + ExtendableTextField cellEditor = new ExtendableTextField(); + cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); + + new ComponentValidator(validatorsDisposable).withValidator(() -> { + String text = cellEditor.getText(); + boolean hasError = !StringUtil.isEmpty(text) && !ourPackagePattern.matcher(text).matches(); + ValidationUtils.setErrorExtension(cellEditor, hasError); + + return validationInfoProducer.apply(text, cellEditor); + }).andRegisterOnDocumentListener(cellEditor).installOn(cellEditor); + + return new DefaultCellEditor(cellEditor); } @Override public TableCellRenderer getRenderer(Item pair) { - return new DefaultTableCellRenderer() { - @NotNull - @Override - public Component getTableCellRendererComponent(JTable table, - Object value, - boolean isSelected, - boolean hasFocus, - int row, - int column) { - Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (!ourPackagePattern.matcher((String)value).matches()) { - component.setForeground(JBColor.RED); - } - return component; - } - }; + return new ValidatingTableCellRendererWrapper(new DefaultTableCellRenderer()). + withCellValidator((value, row, column) -> validationInfoProducer.apply(value, null)); } @Override @@ -85,6 +89,7 @@ class ExcludeTable extends ListTableWithButtons { item.exclude = value; } }; + private static final ColumnInfo SCOPE_COLUMN = new ColumnInfo("Scope") { @Nullable @Override @@ -126,7 +131,13 @@ class ExcludeTable extends ListTableWithButtons { ExcludeTable(@NotNull Project project) { myProject = project; - getTableView().getEmptyText().setText(ApplicationBundle.message("exclude.from.imports.no.exclusions")); + + JBTable table = getTableView(); + table.getEmptyText().setText(ApplicationBundle.message("exclude.from.imports.no.exclusions")); + table.setStriped(false); + new CellTooltipManager(myProject).withCellComponentProvider(CellComponentProvider.forTable(table)).installOn(table); + + Disposer.register(project, validatorsDisposable); } @Override @@ -175,7 +186,7 @@ class ExcludeTable extends ListTableWithButtons { } void reset() { - java.util.List rows = ContainerUtil.newArrayList(); + List rows = ContainerUtil.newArrayList(); for (String s : CodeInsightSettings.getInstance().EXCLUDED_PACKAGES) { rows.add(new Item(s, ExclusionScope.IDE)); } From efe8461e869c6a9a6d9e385a380866d23e9af0f5 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Fri, 1 Feb 2019 16:36:05 +0300 Subject: [PATCH 029/138] IDEA-205679 Modified insets for TableCellRenderers, extracted StatefulValidationCellEditor, minor API changes --- .../options/editor/ExcludeTable.java | 2 +- .../intellij/openapi/ui/ValidationInfo.java | 5 + .../StatefulValidatingCellEditor.java | 92 +++++++++++++++++++ .../ValidatingTableCellRendererWrapper.java | 2 +- .../ui/cellvalidators/ValidationUtils.java | 85 ++++------------- .../fields/ExtendableTextField.java | 7 +- .../ide/plugins/PluginHostsConfigurable.java | 14 ++- ...rculaTableSelectedCellHighlightBorder.java | 2 +- .../ide/ui/laf/darcula/DarculaUIUtil.java | 4 +- .../ide/ui/laf/darcula/darcula.properties | 2 +- .../ui/DarculaEditorTextFieldBorder.java | 4 +- .../ui/laf/darcula/ui/DarculaTextBorder.java | 2 +- .../ide/ui/laf/intellijlaf.properties | 2 +- .../ide/ui/laf/intellijlaf_native.properties | 2 +- .../internal/ui/ComponentPanelTestAction.java | 10 +- 15 files changed, 140 insertions(+), 95 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java diff --git a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java index 6f525bb0c0aa..4268497c9e43 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java +++ b/java/java-impl/src/com/intellij/application/options/editor/ExcludeTable.java @@ -65,7 +65,7 @@ class ExcludeTable extends ListTableWithButtons { new ComponentValidator(validatorsDisposable).withValidator(() -> { String text = cellEditor.getText(); boolean hasError = !StringUtil.isEmpty(text) && !ourPackagePattern.matcher(text).matches(); - ValidationUtils.setErrorExtension(cellEditor, hasError); + ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, hasError); return validationInfoProducer.apply(text, cellEditor); }).andRegisterOnDocumentListener(cellEditor).installOn(cellEditor); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java b/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java index 5a2fe565cd22..912823ddb56a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ValidationInfo.java @@ -68,6 +68,11 @@ public final class ValidationInfo { return this; } + public ValidationInfo forComponent(@Nullable JComponent component) { + ValidationInfo result = new ValidationInfo(message, component); + return warning ? result.asWarning() : result; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java new file mode 100644 index 000000000000..0fa389fba362 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java @@ -0,0 +1,92 @@ +// Copyright 2000-2019 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.openapi.ui.cellvalidators; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.DocumentAdapter; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ItemListener; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY; + +public class StatefulValidatingCellEditor extends DefaultCellEditor implements Supplier { + private Consumer stateUpdater = (vi) -> {}; + + public StatefulValidatingCellEditor(JTextField textField, Disposable disposable) { + super(textField); + editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); + new ComponentValidator(disposable).withValidator(this).installOn(editorComponent); + + DocumentListener dl = new DocumentAdapter() { + @Override + protected void textChanged(@NotNull DocumentEvent e) { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + } + }; + + textField.getDocument().addDocumentListener(dl); + Disposer.register(disposable, () -> textField.getDocument().removeDocumentListener(dl)); + } + + public StatefulValidatingCellEditor(JComboBox comboBox, Disposable disposable) { + super(comboBox); + editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); + new ComponentValidator(disposable).withValidator(this).installOn(editorComponent); + + ItemListener il = e -> { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + }; + + comboBox.addItemListener(il); + Disposer.register(disposable, () -> comboBox.removeItemListener(il)); + } + + public StatefulValidatingCellEditor withStateUpdater(@NotNull Consumer stateUpdater) { + this.stateUpdater = stateUpdater; + return this; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + JComponent editor = (JComponent)super.getTableCellEditorComponent(table, value, isSelected, row, column); + JComponent renderer = (JComponent)table.getCellRenderer(row, column).getTableCellRendererComponent(table, value, isSelected, true, row, column); + ValidationInfo cellInfo = renderer != null ? (ValidationInfo)renderer.getClientProperty(CELL_VALIDATION_PROPERTY) : null; + if (cellInfo != null) { + editor.putClientProperty(CELL_VALIDATION_PROPERTY, cellInfo.forComponent(editor)); + ComponentValidator.getInstance(editor).ifPresent(ComponentValidator::revalidate); + } + return editor; + } + + @Override + public boolean stopCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + return super.stopCellEditing(); + } + + @Override + public void cancelCellEditing() { + editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); + ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); + super.cancelCellEditing(); + } + + @Override + public ValidationInfo get() { + ValidationInfo info = (ValidationInfo)editorComponent.getClientProperty(CELL_VALIDATION_PROPERTY); + stateUpdater.accept(info); + return info; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java index 98c9d7808bcc..356cede26872 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -54,7 +54,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem if (cellValidator != null) { ValidationInfo result = cellValidator.validate(value, row, column); iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); - iconLabel.setBorder(result == null ? null: JBUI.Borders.emptyRight(4)); + iconLabel.setBorder(result == null ? null: JBUI.Borders.emptyRight(3)); putClientProperty(CELL_VALIDATION_PROPERTY, result); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java index 4730b43fc7d5..a987340697ca 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidationUtils.java @@ -2,21 +2,10 @@ package com.intellij.openapi.ui.cellvalidators; import com.intellij.icons.AllIcons; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.ui.ComponentValidator; import com.intellij.openapi.ui.ValidationInfo; -import com.intellij.openapi.util.Disposer; -import com.intellij.ui.DocumentAdapter; import com.intellij.ui.components.fields.ExtendableTextComponent; -import com.intellij.ui.components.fields.ExtendableTextField; import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import java.awt.*; - -import static com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper.CELL_VALIDATION_PROPERTY; +import org.jetbrains.annotations.Nullable; public final class ValidationUtils { private ValidationUtils() {} @@ -24,63 +13,25 @@ public final class ValidationUtils { public final static ExtendableTextComponent.Extension ERROR_EXTENSION = ExtendableTextComponent.Extension.create(AllIcons.General.BalloonError, null, null); - public static void setErrorExtension(ExtendableTextComponent editor, boolean set) { - if (!set) { + public final static ExtendableTextComponent.Extension WARNING_EXTENSION = + ExtendableTextComponent.Extension.create(AllIcons.General.BalloonWarning, null, null); + + public static void setExtension(@NotNull ExtendableTextComponent editor, @NotNull ExtendableTextComponent.Extension extension, boolean set) { + if (set) { + editor.addExtension(extension); + } else { + editor.removeExtension(extension); + } + } + + public static void setExtension(@NotNull ExtendableTextComponent editor, @Nullable ValidationInfo vi) { + if (vi == null) { editor.removeExtension(ERROR_EXTENSION); - } else if (editor instanceof JComponent && ((JComponent)editor).getClientProperty("JComponent.outline") == null) { + editor.removeExtension(WARNING_EXTENSION); + } else if (vi.warning) { + editor.addExtension(WARNING_EXTENSION); + } else { editor.addExtension(ERROR_EXTENSION); } } - - public static class StatefulValidatingEditor extends DefaultCellEditor { - public StatefulValidatingEditor(Disposable disposable) { - super(new ExtendableTextField()); - editorComponent.putClientProperty("JComponent.compactHeight", Boolean.TRUE); - - ExtendableTextField extendableTextField = (ExtendableTextField)editorComponent; - - new ComponentValidator(disposable).withValidator(() -> { - ValidationInfo info = (ValidationInfo)extendableTextField.getClientProperty(CELL_VALIDATION_PROPERTY); - setErrorExtension(extendableTextField, info != null); - return info; - }).installOn(extendableTextField); - - DocumentListener dl = new DocumentAdapter() { - @Override - protected void textChanged(@NotNull DocumentEvent e) { - editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); - ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); - } - }; - - extendableTextField.getDocument().addDocumentListener(dl); - Disposer.register(disposable, () -> extendableTextField.getDocument().removeDocumentListener(dl)); - } - - @Override - public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { - JComponent editor = (JComponent)super.getTableCellEditorComponent(table, value, isSelected, row, column); - JComponent renderer = (JComponent)table.getCellRenderer(row, column).getTableCellRendererComponent(table, value, isSelected, true, row, column); - ValidationInfo cellInfo = renderer != null ? (ValidationInfo)renderer.getClientProperty(CELL_VALIDATION_PROPERTY) : null; - if (cellInfo != null) { - editor.putClientProperty(CELL_VALIDATION_PROPERTY, new ValidationInfo(cellInfo.message, editor)); - ComponentValidator.getInstance(editor).ifPresent(ComponentValidator::revalidate); - } - return editor; - } - - @Override - public boolean stopCellEditing() { - editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); - ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); - return super.stopCellEditing(); - } - - @Override - public void cancelCellEditing() { - editorComponent.putClientProperty(CELL_VALIDATION_PROPERTY, null); - ComponentValidator.getInstance(editorComponent).ifPresent(ComponentValidator::revalidate); - super.cancelCellEditing(); - } - } } diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java index f1ed33116eae..391da221ae0d 100644 --- a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java @@ -60,8 +60,11 @@ public class ExtendableTextField extends JBTextField implements ExtendableTextCo @Override public void addExtension(@NotNull Extension extension) { - List extensions = new ArrayList<>(getExtensions()); - if (extensions.add(extension)) setExtensions(extensions); + if (!getExtensions().contains(extension)) { + List extensions = new ArrayList<>(getExtensions()); + extensions.add(extension); + setExtensions(extensions); + } } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index 39656adfc8fd..5cdd5310b6f1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -11,9 +11,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.ui.ValidationInfo; -import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; -import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; -import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; +import com.intellij.openapi.ui.cellvalidators.*; import com.intellij.openapi.updateSettings.impl.UpdateSettings; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; @@ -22,6 +20,7 @@ import com.intellij.ui.AnimatedIcon; import com.intellij.ui.ColoredTableCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.ui.table.JBTable; import com.intellij.util.io.URLUtil; import com.intellij.util.ui.ColumnInfo; @@ -39,8 +38,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import static com.intellij.openapi.ui.cellvalidators.ValidationUtils.StatefulValidatingEditor; - public class PluginHostsConfigurable implements Configurable.NoScroll, Configurable { private final ListTableModel myModel = new ListTableModel() { @Override @@ -138,7 +135,9 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - DefaultCellEditor editor = new StatefulValidatingEditor(myDisposable); + ExtendableTextField cellEditor = new ExtendableTextField(); + DefaultCellEditor editor = new StatefulValidatingCellEditor(cellEditor, myDisposable). + withStateUpdater(vi -> ValidationUtils.setExtension(cellEditor, vi)); editor.setClickCountToStart(1); myTable.setDefaultEditor(Object.class, editor); @@ -149,7 +148,6 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura protected void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column) { if (row >= 0 && row < myModel.getRowCount()) { UrlInfo info = myModel.getRowValue(row); - setBorder(null); setForeground(selected ? table.getSelectionForeground() : table.getForeground()); setBackground(selected ? table.getSelectionBackground() : table.getBackground()); append(info.name, SimpleTextAttributes.REGULAR_ATTRIBUTES); @@ -161,7 +159,7 @@ public class PluginHostsConfigurable implements Configurable.NoScroll, Configura return attributes; } }). - bindToEditorSize(editor.getComponent()::getPreferredSize). + bindToEditorSize(cellEditor::getPreferredSize). withCellValidator((value, row, column) -> { if (row >= 0 && row < myModel.getRowCount()) { UrlInfo info = myModel.getRowValue(row); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java index 83f8777f1915..c62afbf1e859 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaTableSelectedCellHighlightBorder.java @@ -33,7 +33,7 @@ public class DarculaTableSelectedCellHighlightBorder extends CompoundBorder impl } protected Border createInsideBorder() { - return JBUI.Borders.empty(3); + return JBUI.Borders.empty(2); } protected Color createFocusBorderColor() { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java index 04e1a85b1aba..8bfa6b441fc2 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java @@ -262,8 +262,8 @@ public class DarculaUIUtil { @Override public Insets getBorderInsets(Component c) { - return isTableCellEditor(c) || isCompact(c) ? JBUI.insets(2).asUIResource() : - isComboBoxEditor(c) ? JBUI.insets(2, 3).asUIResource() : JBUI.insets(5, 8).asUIResource(); + return isTableCellEditor(c) || isCompact(c) || isComboBoxEditor(c) ? + JBUI.insets(2, 3).asUIResource() : JBUI.insets(5, 8).asUIResource(); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index e10cbdd8358e..9a6d9af1046c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -64,7 +64,7 @@ TableHeaderUI=com.intellij.ide.ui.laf.darcula.DarculaTableHeaderUI Table.gridColor=2c2c2c Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,3,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.darcula.DarculaTableSelectedCellHighlightBorder #just to suppress border painters diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java index 7c4cb93cf038..245bfc39abaf 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java @@ -119,8 +119,8 @@ public class DarculaEditorTextFieldBorder extends DarculaTextBorder implements V @Override public Insets getBorderInsets(Component c) { - return isTableCellEditor(c) || isCompact(c) ? JBUI.insets(2).asUIResource() : - isComboBoxEditor(c) ? JBUI.insets(2, 3).asUIResource() : JBUI.insets(6, 8).asUIResource(); + return isTableCellEditor(c) || isCompact(c) || isComboBoxEditor(c) ? + JBUI.insets(2, 3).asUIResource() : JBUI.insets(6, 8).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java index c89fa4bedef3..3ab1b20e12e3 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextBorder.java @@ -25,7 +25,7 @@ import static com.intellij.ide.ui.laf.darcula.DarculaUIUtil.*; public class DarculaTextBorder implements Border, UIResource, ErrorBorderCapable { @Override public Insets getBorderInsets(Component c) { - return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 2 : 3).asUIResource(); + return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 2 : 3, 3).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index 35e13a1c189c..e703a742357a 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -60,7 +60,7 @@ Table.gridColor=dddddd Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown Table.background=ffffff -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,3,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.darcula.DarculaTableSelectedCellHighlightBorder #just to suppress border painters diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index aa2c33cc8e29..b8f28fd37b2b 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -62,7 +62,7 @@ Table.gridColor=dddddd Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown Table.background=ffffff -Table.cellNoFocusBorder=4,4,4,4 +Table.cellNoFocusBorder=3,3,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.intellij.WinIntelliJTableSelectedCellHighlightBorder LabelUI=com.intellij.ide.ui.laf.darcula.ui.DarculaLabelUI diff --git a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java index 2b05680e3310..e8f101ce35a8 100644 --- a/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java +++ b/platform/platform-impl/src/com/intellij/internal/ui/ComponentPanelTestAction.java @@ -10,10 +10,7 @@ import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.*; -import com.intellij.openapi.ui.cellvalidators.CellComponentProvider; -import com.intellij.openapi.ui.cellvalidators.CellTooltipManager; -import com.intellij.openapi.ui.cellvalidators.ValidatingTableCellRendererWrapper; -import com.intellij.openapi.ui.cellvalidators.ValidationUtils; +import com.intellij.openapi.ui.cellvalidators.*; import com.intellij.openapi.ui.panel.ProgressPanel; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; @@ -293,12 +290,11 @@ public class ComponentPanelTestAction extends DumbAwareAction { ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, "Open file", () -> System.out.println("Table browse clicked")); cellEditor.addExtension(browseExtension); - cellEditor.putClientProperty(DarculaUIUtil.COMPACT_PROPERTY, Boolean.TRUE); new ComponentValidator(getDisposable()).withValidator(() -> { boolean isAllowed = ALLOWED_VALUES.contains(cellEditor.getText()); - ValidationUtils.setErrorExtension(cellEditor, !isAllowed); + ValidationUtils.setExtension(cellEditor, ValidationUtils.ERROR_EXTENSION, !isAllowed); return isAllowed ? null : validationInfoGenerator.apply(cellEditor.getText(), cellEditor); }).withHyperlinkListener(hyperlinkListener). andRegisterOnDocumentListener(cellEditor). @@ -317,7 +313,7 @@ public class ComponentPanelTestAction extends DumbAwareAction { JComboBox rightEditor = new ComboBox<>(Arrays.stream(data).map(i -> Integer.valueOf(i[1])).toArray(Integer[]::new)); col = table.getColumnModel().getColumn(1); - col.setCellEditor(new DefaultCellEditor(rightEditor)); + col.setCellEditor(new StatefulValidatingCellEditor(rightEditor, getDisposable())); col.setCellRenderer(new ValidatingTableCellRendererWrapper(new ColoredTableCellRenderer() { { setIpad(JBUI.emptyInsets()); } // Reset standard pads From d080d56b4244b0cfe21e0206bf1942d7f95c9d96 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Fri, 1 Feb 2019 16:46:18 +0300 Subject: [PATCH 030/138] IDEA-205679 Tag API Experimental --- .../openapi/ui/cellvalidators/CellComponentProvider.java | 6 +++--- .../openapi/ui/cellvalidators/CellTooltipManager.java | 5 +++++ .../ui/cellvalidators/StatefulValidatingCellEditor.java | 2 ++ .../openapi/ui/cellvalidators/TableCellValidator.java | 2 ++ .../cellvalidators/ValidatingTableCellRendererWrapper.java | 4 ++++ 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java index 5f87d6cbc6d7..84f20e2a411e 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellComponentProvider.java @@ -1,6 +1,7 @@ // Copyright 2000-2019 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.openapi.ui.cellvalidators; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,6 +10,7 @@ import javax.swing.table.TableCellRenderer; import java.awt.*; import java.awt.event.MouseEvent; +@ApiStatus.Experimental public abstract class CellComponentProvider { @NotNull protected final C owner; @@ -62,6 +64,4 @@ public abstract class CellComponentProvider { return owner.getCellRect(owner.rowAtPoint(p), owner.columnAtPoint(p), true); } } -} - - +} \ No newline at end of file diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java index be0932014c07..6434a5a7e922 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/CellTooltipManager.java @@ -11,6 +11,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.Alarm; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,20 +42,24 @@ public final class CellTooltipManager { private boolean isOverPopup; private boolean isClosing; + @ApiStatus.Experimental public CellTooltipManager(@NotNull Disposable parentDisposable) { this.parentDisposable = parentDisposable; } + @ApiStatus.Experimental public CellTooltipManager withCellComponentProvider(@NotNull CellComponentProvider cellComponentProvider) { this.cellComponentProvider = cellComponentProvider; return this; } + @ApiStatus.Experimental public CellTooltipManager withHyperlinkListener(@NotNull HyperlinkListener hyperlinkListener) { this.hyperlinkListener = hyperlinkListener; return this; } + @ApiStatus.Experimental public void installOn(@NotNull JComponent component) { MouseAdapter mouseListener = new ValidationMouseListener(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java index 0fa389fba362..b1d9743bfba0 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/StatefulValidatingCellEditor.java @@ -6,6 +6,7 @@ import com.intellij.openapi.ui.ComponentValidator; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.Disposer; import com.intellij.ui.DocumentAdapter; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -52,6 +53,7 @@ public class StatefulValidatingCellEditor extends DefaultCellEditor implements S Disposer.register(disposable, () -> comboBox.removeItemListener(il)); } + @ApiStatus.Experimental public StatefulValidatingCellEditor withStateUpdater(@NotNull Consumer stateUpdater) { this.stateUpdater = stateUpdater; return this; diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java index 0c10da752e04..0fbb42759f27 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/TableCellValidator.java @@ -2,7 +2,9 @@ package com.intellij.openapi.ui.cellvalidators; import com.intellij.openapi.ui.ValidationInfo; +import org.jetbrains.annotations.ApiStatus; +@ApiStatus.Experimental public interface TableCellValidator { ValidationInfo validate(Object value, int row, int column); } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java index 356cede26872..f3edfeade941 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -5,6 +5,7 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.ui.CellRendererPanel; import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -21,6 +22,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem private Supplier editorSizeSupplier = () -> JBUI.emptySize(); private TableCellValidator cellValidator; + @ApiStatus.Experimental public ValidatingTableCellRendererWrapper(TableCellRenderer delegate) { this.delegate = delegate; setLayout(new BorderLayout(0, 0)); @@ -30,11 +32,13 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem setName("Table.cellRenderer"); } + @ApiStatus.Experimental public ValidatingTableCellRendererWrapper bindToEditorSize(@NotNull Supplier editorSizeSupplier) { this.editorSizeSupplier = editorSizeSupplier; return this; } + @ApiStatus.Experimental public ValidatingTableCellRendererWrapper withCellValidator(@NotNull TableCellValidator cellValidator) { this.cellValidator = cellValidator; return this; From a3cb260a052e4558ee9830a03aacd7e7c5eb7da0 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Mon, 4 Feb 2019 14:15:08 +0300 Subject: [PATCH 031/138] IDEA-205679 Windows10 insets adjusted --- .../ValidatingTableCellRendererWrapper.java | 8 +++++++- .../WinIntelliJTableSelectedCellHighlightBorder.java | 2 +- .../ide/ui/laf/intellij/WinIntelliJTextBorder.java | 4 +++- .../com/intellij/ide/ui/laf/intellijlaf_native.properties | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java index f3edfeade941..3cf1e24afd91 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/cellvalidators/ValidatingTableCellRendererWrapper.java @@ -5,10 +5,12 @@ import com.intellij.icons.AllIcons; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.ui.CellRendererPanel; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import javax.swing.border.Border; import javax.swing.table.TableCellRenderer; import java.awt.*; import java.util.function.Supplier; @@ -58,7 +60,7 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem if (cellValidator != null) { ValidationInfo result = cellValidator.validate(value, row, column); iconLabel.setIcon(result == null ? null : result.warning ? AllIcons.General.BalloonWarning : AllIcons.General.BalloonError); - iconLabel.setBorder(result == null ? null: JBUI.Borders.emptyRight(3)); + iconLabel.setBorder(result == null ? null: iconBorder()); putClientProperty(CELL_VALIDATION_PROPERTY, result); } @@ -70,6 +72,10 @@ public class ValidatingTableCellRendererWrapper extends CellRendererPanel implem return this; } + private static Border iconBorder() { + return JBUI.Borders.emptyRight(UIUtil.isUnderWin10LookAndFeel() ? 4 : 3); + } + @Override protected void paintComponent(Graphics g) { g.setColor(getBackground()); diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java index c508e603c979..e92e81a3e267 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTableSelectedCellHighlightBorder.java @@ -9,6 +9,6 @@ import javax.swing.border.Border; public class WinIntelliJTableSelectedCellHighlightBorder extends DarculaTableSelectedCellHighlightBorder { @Override protected Border createInsideBorder() { - return JBUI.Borders.empty(2); + return JBUI.Borders.empty(2, 3, 2, 2); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java index a6b2a05d2f7c..ca25020d3bce 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJTextBorder.java @@ -35,7 +35,9 @@ public class WinIntelliJTextBorder extends DarculaTextBorder { @Override public Insets getBorderInsets(Component c) { - return JBUI.insets(isTableCellEditor(c) || isCompact(c) ? 0 : 1).asUIResource(); + return isTableCellEditor(c) || isCompact(c) ? + JBUI.insets(1, 1, 1, 4).asUIResource() : + JBUI.insets(1).asUIResource(); } @Override diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index b8f28fd37b2b..0ea0a0166724 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -62,7 +62,7 @@ Table.gridColor=dddddd Table.ascendingSortIcon=AllIcons.General.ArrowUp Table.descendingSortIcon=AllIcons.General.SplitDown Table.background=ffffff -Table.cellNoFocusBorder=3,3,3,3 +Table.cellNoFocusBorder=3,4,3,3 Table.focusSelectedCellHighlightBorder=com.intellij.ide.ui.laf.intellij.WinIntelliJTableSelectedCellHighlightBorder LabelUI=com.intellij.ide.ui.laf.darcula.ui.DarculaLabelUI From 6c2d86a6fff938f669d1424251bd117c6bb798ed Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 13:15:58 +0100 Subject: [PATCH 032/138] FUS: add information about the application to 'ide.start' --- .../LifecycleUsageTriggerCollector.java | 15 ++++++++++++++- .../statistic/eventLog/EventLogConfiguration.kt | 2 +- .../utils/StatisticsUploadAssistant.java | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java index d71e40246473..4e4e4acbeeed 100644 --- a/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java +++ b/platform/platform-impl/src/com/intellij/featureStatistics/fusCollectors/LifecycleUsageTriggerCollector.java @@ -3,6 +3,8 @@ package com.intellij.featureStatistics.fusCollectors; import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger; +import com.intellij.internal.statistic.utils.StatisticsUploadAssistant; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -14,7 +16,18 @@ public class LifecycleUsageTriggerCollector { private static final String LIFECYCLE = "lifecycle"; public static void onIdeStart() { - FUCounterUsageLogger.getInstance().logEvent(LIFECYCLE, "ide.start"); + final FeatureUsageData data = new FeatureUsageData().addData("eap", ApplicationManager.getApplication().isEAP()); + addIfTrue(data, "test", StatisticsUploadAssistant.isTestStatisticsEnabled()); + addIfTrue(data, "command_line", ApplicationManager.getApplication().isCommandLine()); + addIfTrue(data, "internal", ApplicationManager.getApplication().isInternal()); + addIfTrue(data, "headless", ApplicationManager.getApplication().isHeadlessEnvironment()); + FUCounterUsageLogger.getInstance().logEvent(LIFECYCLE, "ide.start", data); + } + + private static void addIfTrue(@NotNull FeatureUsageData data, @NotNull String key, boolean value) { + if (value) { + data.addData(key, value); + } } public static void onIdeClose(boolean restart) { diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt index 67323521b21b..c2466f9752e5 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt +++ b/platform/platform-impl/src/com/intellij/internal/statistic/eventLog/EventLogConfiguration.kt @@ -17,7 +17,7 @@ import java.util.prefs.Preferences object EventLogConfiguration { private val LOG = Logger.getInstance(EventLogConfiguration::class.java) private const val SALT_PREFERENCE_KEY = "feature_usage_event_log_salt" - const val version: Int = 6 + const val version: Int = 7 val sessionId: String = UUID.randomUUID().toString().shortedUUID() diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java b/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java index ace9675aee45..717fa7778c53 100755 --- a/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/utils/StatisticsUploadAssistant.java @@ -66,6 +66,10 @@ public class StatisticsUploadAssistant { return (settings != null && settings.isAllowed()) || Boolean.getBoolean(ENABLE_LOCAL_STATISTICS_WITHOUT_REPORT); } + public static boolean isTestStatisticsEnabled() { + return Boolean.getBoolean(ENABLE_LOCAL_STATISTICS_WITHOUT_REPORT); + } + public static void updateSentTime() { UsageStatisticsPersistenceComponent.getInstance().setSentTime(System.currentTimeMillis()); } From c843880c85e378ad943c5227e50479b7ffdaf97d Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 4 Feb 2019 15:29:43 +0300 Subject: [PATCH 033/138] IDEA-206591 Rename Mac OS X to macOS --- .../src/messages/ApplicationBundle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 45391486b753..8de86b917e7e 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -496,9 +496,9 @@ checkbox.do.not.indent.top.level.class.members=Do not indent top level class mem checkbox.use.relative.indents=Use indents relative to expression start tooltip.indent.must.be.multiple.of.tab.size.for.smart.tabs.to.operate=Indent must be multiple of tab size for smart tabs to operate combobox.crlf.system.dependent=System-Dependent -combobox.crlf.unix=Unix and OS X (\\n) +combobox.crlf.unix=Unix and macOS (\\n) combobox.crlf.windows=Windows (\\r\\n) -combobox.crlf.mac=Classic Mac (\\r) +combobox.crlf.mac=Classic macOS (\\r) group.tabs.and.indents=Tabs and Indents checkbox.indent.use.same.settings.for.all.file.types=Use default indent options (General) tab.indent.other=Other From 0791e9d7f5cf4f796190d173a798c7b12d7fc786 Mon Sep 17 00:00:00 2001 From: Konstantin Aleev Date: Sun, 3 Feb 2019 19:33:42 +0300 Subject: [PATCH 034/138] FUS-271 Don't report navigators from proprietary plugins `spring.boot.mvc.usages` - report a place for statistics event in a context --- .../com/intellij/openapi/actionSystem/ActionPlaces.java | 7 +++++-- .../openapi/editor/impl/EditorGutterComponentImpl.java | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java index ca6813684e47..cc1e39a70d68 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java @@ -40,10 +40,13 @@ public abstract class ActionPlaces { public static final String EDITOR_TOOLBAR = "EditorToolbar"; public static final String EDITOR_TAB_POPUP = "EditorTabPopup"; public static final String EDITOR_TAB = "EditorTab"; + public static final String EDITOR_GUTTER = "ICON_NAVIGATION"; + public static final String EDITOR_GUTTER_POPUP = "ICON_NAVIGATION_SECONDARY_BUTTON"; public static final String COMMANDER_POPUP = "CommanderPopup"; public static final String COMMANDER_TOOLBAR = "CommanderToolbar"; public static final String CONTEXT_TOOLBAR = "ContextToolbar"; public static final String TOOLWINDOW_TITLE = "ToolwindowTitle"; + public static final String TOOLWINDOW_CONTENT = "ToolwindowContent"; public static final String PROJECT_VIEW_POPUP = "ProjectViewPopup"; public static final String PROJECT_VIEW_TOOLBAR = "ProjectViewToolbar"; @@ -151,7 +154,7 @@ public abstract class ActionPlaces { FILEHISTORY_VIEW_TOOLBAR, RUN_CONFIGURATIONS_COMBOBOX, WELCOME_SCREEN, CHANGES_VIEW_TOOLBAR, DATABASE_VIEW_TOOLBAR, ACTION_PLACE_QUICK_LIST_POPUP_ACTION, PHING_EXPLORER_TOOLBAR, DOCK_MENU, PHING_MESSAGES_TOOLBAR, DIFF_TOOLBAR, ANALYZE_STACKTRACE_PANEL_TOOLBAR, TOUCHBAR_GENERAL, COMPOSER_EDITOR_NOTIFICATION_PANEL, COMPOSER_EDITOR_NOTIFICATION_PANEL_EXTRA, - COMPOSER_LOG_RERUN + COMPOSER_LOG_RERUN, EDITOR_GUTTER, TOOLWINDOW_CONTENT ); private static final Set ourPopupPlaces = ContainerUtil.newHashSet( @@ -163,7 +166,7 @@ public abstract class ActionPlaces { GUI_DESIGNER_PROPERTY_INSPECTOR_POPUP, CREATE_EJB_POPUP, CHANGES_VIEW_POPUP, DATABASE_VIEW_POPUP, REMOTE_HOST_VIEW_POPUP, REMOTE_HOST_DIALOG_POPUP, TFS_TREE_POPUP, ACTION_PLACE_VCS_QUICK_LIST_POPUP_ACTION, PHING_EXPLORER_POPUP, NAVIGATION_BAR_POPUP, JS_BUILD_TOOL_POPUP, - V8_CPU_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, RUN_DASHBOARD_POPUP + V8_CPU_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, V8_HEAP_PROFILING_POPUP, RUN_DASHBOARD_POPUP, EDITOR_GUTTER_POPUP ); private static final String POPUP_PREFIX = "popup@"; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 43bc0de4324e..8295c8f3d836 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -1739,7 +1739,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse : renderer.getClickAction(); } if (clickAction != null) { - performAction(clickAction, e, "ICON_NAVIGATION", myEditor.getDataContext()); + performAction(clickAction, e, ActionPlaces.EDITOR_GUTTER, myEditor.getDataContext()); repaint(); e.consume(); } @@ -1959,7 +1959,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse if (renderer != null) { AnAction rightButtonAction = renderer.getRightButtonClickAction(); if (rightButtonAction != null) { - performAction(rightButtonAction, e, "ICON_NAVIGATION_SECONDARY_BUTTON", myEditor.getDataContext()); + performAction(rightButtonAction, e, ActionPlaces.EDITOR_GUTTER_POPUP, myEditor.getDataContext()); e.consume(); } else { From f7e239460b53b527ef936cede8cd6d53e6467a91 Mon Sep 17 00:00:00 2001 From: Konstantin Aleev Date: Sun, 3 Feb 2019 19:54:17 +0300 Subject: [PATCH 035/138] FUS-282 Report configuration types developed in JB in `run.dashboard` --- .../RunDashboardUsagesCollector.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java index 60b42d22c242..ea756a58610c 100644 --- a/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java +++ b/platform/lang-impl/src/com/intellij/execution/dashboard/RunDashboardUsagesCollector.java @@ -1,13 +1,17 @@ // 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.dashboard; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.internal.statistic.beans.UsageDescriptor; import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector; +import com.intellij.internal.statistic.utils.PluginInfoDetectorKt; import com.intellij.internal.statistic.utils.StatisticsUtilKt; import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -24,9 +28,19 @@ public class RunDashboardUsagesCollector extends ProjectUsagesCollector { @Override public Set getUsages(@NotNull Project project) { final Set usages = new HashSet<>(); - final Set types = RunDashboardManager.getInstance(project).getTypes(); - usages.add(StatisticsUtilKt.getBooleanUsage("run.dashboard", !types.isEmpty())); - types.forEach(type -> usages.add(new UsageDescriptor(type))); + final Set dashboardTypes = RunDashboardManager.getInstance(project).getTypes(); + usages.add(StatisticsUtilKt.getBooleanUsage("run.dashboard", !dashboardTypes.isEmpty())); + if (!dashboardTypes.isEmpty()) { + List configurationTypes = ConfigurationType.CONFIGURATION_TYPE_EP.getExtensionList(); + for (String dashboardType : dashboardTypes) { + ConfigurationType configurationType = ContainerUtil.find(configurationTypes, type -> type.getId().equals(dashboardType)); + if (configurationType == null) continue; + + String key = PluginInfoDetectorKt.getPluginInfo(configurationType.getClass()).isDevelopedByJetBrains() ? + dashboardType : "third.party"; + usages.add(new UsageDescriptor(key)); + } + } return usages; } } From 0630defe58c2c80d37b1962c88f0bafea6e22c05 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Feb 2019 13:49:03 +0100 Subject: [PATCH 036/138] IDEA-CR-42201 Accessing data context from a pooled thread is likely to lead to exceptions --- .../src/com/intellij/ide/actions/SaveAllAction.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt b/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt index f22e7e10ecf4..81b429e1b65a 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt +++ b/platform/platform-impl/src/com/intellij/ide/actions/SaveAllAction.kt @@ -18,9 +18,11 @@ open class SaveAllAction : AnAction(), DumbAware { override fun actionPerformed(e: AnActionEvent) { CommonDataKeys.EDITOR.getData(e.dataContext)?.let(::stripSpacesFromCaretLines) + val project = CommonDataKeys.PROJECT.getData(e.dataContext) GlobalScope.launch(pooledThreadContext) { - saveDocumentsAndProjectsAndApp(onlyProject = CommonDataKeys.PROJECT.getData(e.dataContext), - isForceSavingAllSettings = true) + if (project == null || !project.isDisposed) { + saveDocumentsAndProjectsAndApp(onlyProject = project, isForceSavingAllSettings = true) + } } } } From 1b756043a4e31d72779e8d89be28503b36ca4196 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Mon, 4 Feb 2019 15:49:26 +0300 Subject: [PATCH 037/138] EA-135839 - IOOBE: SegmentArray.offsetOutOfRange fix case when offset <= 0. Not sure how it can happen though --- .../com/intellij/codeInsight/editorActions/TypedHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java index 0bffd17cb0d5..51bc59e370b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TypedHandler.java @@ -507,7 +507,7 @@ public class TypedHandler extends TypedActionHandlerBase { } } - if (isOpeningQuote(editor, quoteHandler, offset - 1) && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) { + if (offset > 0 && isOpeningQuote(editor, quoteHandler, offset - 1) && hasNonClosedLiterals(editor, quoteHandler, offset - 1)) { if (offset == document.getTextLength() || !Character.isUnicodeIdentifierPart(document.getCharsSequence().charAt(offset))) { //any better heuristic or an API? document.insertString(offset, String.valueOf(quote)); From 7b3c67fd5b0194da2b5f28468e778c31bc27a6ad Mon Sep 17 00:00:00 2001 From: Alexandr Evstigneev Date: Thu, 31 Jan 2019 10:11:55 +0300 Subject: [PATCH 038/138] Added time measurements for a focus zones computation by a single provider (warns if longer than 100ms) Also: Added segments caching to avoid multiple computations on the same psi file IDEA-CR-42682 --- .../impl/focusMode/FocusModePassFactory.java | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java index 626d8f9caf4d..9df9ed9b646e 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java @@ -6,6 +6,7 @@ import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; import com.intellij.lang.LanguageExtension; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -13,10 +14,14 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.impl.FocusModeModel; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,6 +30,8 @@ import java.util.List; public class FocusModePassFactory implements TextEditorHighlightingPassFactory { private static final LanguageExtension EP_NAME = new LanguageExtension<>("com.intellij.focusModeProvider"); + private static final long MAX_ALLOWED_TIME = 100; + private static final Logger LOG = Logger.getInstance(FocusModePassFactory.class); public FocusModePassFactory(@NotNull TextEditorHighlightingPassRegistrar highlightingPassRegistrar) { highlightingPassRegistrar.registerTextEditorHighlightingPass(this, null, null, false, -1); @@ -45,12 +52,32 @@ public class FocusModePassFactory implements TextEditorHighlightingPassFactory { @Nullable public static List calcFocusZones(@Nullable PsiFile file) { if (file == null || !isEnabled()) return null; - FileViewProvider provider = file.getViewProvider(); + return CachedValuesManager.getCachedValue(file, () -> { + FileViewProvider provider = file.getViewProvider(); - return EP_NAME.allForLanguageOrAny(provider.getBaseLanguage()).stream() - .map(p -> p.calcFocusZones(file)) - .map(l -> ContainerUtil.append(l, file.getTextRange())) - .findFirst().orElse(null); + List segments = EP_NAME.allForLanguageOrAny(provider.getBaseLanguage()).stream() + .map(p -> calcFocusZones(p, file)) + .map(l -> ContainerUtil.append(l, file.getTextRange())) + .findFirst().orElse(null); + return CachedValueProvider.Result.create(segments, file); + }); + } + + /** + * Computes focus zones for the {@code psiFile} using {@code focusModeProvider}. Additionally warns, if zones building took too long + * (longer than {@link #MAX_ALLOWED_TIME} ms. + */ + @NotNull + private static List calcFocusZones(@NotNull FocusModeProvider focusModeProvider, @NotNull PsiFile psiFile) { + Ref> resultRef = Ref.create(); + long executionTime = TimeoutUtil.runAndGetExecutionTime(() -> resultRef.set(focusModeProvider.calcFocusZones(psiFile))); + if (executionTime > MAX_ALLOWED_TIME) { + LOG.warn("Focus zones collecting took too long: " + executionTime + "ms; " + + "Provider: " + focusModeProvider.getClass().getSimpleName() + "; " + + "File size: " + psiFile.getTextLength() + "; " + + "Ranges collected: " + resultRef.get().size()); + } + return resultRef.get(); } public static void setToEditor(@NotNull List zones, Editor editor) { From a7902b6a54196716ac56dc95eb3c65dfd2bbf2c4 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Mon, 4 Feb 2019 16:06:54 +0300 Subject: [PATCH 039/138] IDEA-124595 - action icon --- resources/src/idea/JavaActions.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml index 01717a7e65a6..5deff17095d2 100644 --- a/resources/src/idea/JavaActions.xml +++ b/resources/src/idea/JavaActions.xml @@ -226,7 +226,8 @@
- + From 5a69eb809fb0ae305cebf00d05e25932570af380 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 4 Feb 2019 16:10:15 +0300 Subject: [PATCH 040/138] add code commentary to explain classloader choosing (IDEA-CR-42783) --- platform/util/src/com/intellij/util/ObjectUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/util/src/com/intellij/util/ObjectUtils.java b/platform/util/src/com/intellij/util/ObjectUtils.java index 0d06d32cfb71..b49c56372335 100644 --- a/platform/util/src/com/intellij/util/ObjectUtils.java +++ b/platform/util/src/com/intellij/util/ObjectUtils.java @@ -60,6 +60,8 @@ public class ObjectUtils { if (!ofInterface.isInterface()) { throw new IllegalArgumentException("Expected interface but got: " + ofInterface); } + // java.lang.reflect.Proxy.ProxyClassFactory fails if the class is not available via the classloader. + // We must use interface own classloader because classes from plugins are not available via ObjectUtils' classloader. //noinspection unchecked return (T)Proxy.newProxyInstance(ofInterface.getClassLoader(), new Class[]{ofInterface}, new InvocationHandler() { @Override From e6e0952c826b788979f64691228e55523a7126c7 Mon Sep 17 00:00:00 2001 From: Anton Lobov Date: Mon, 4 Feb 2019 14:11:33 +0100 Subject: [PATCH 041/138] RUBY-23469 follow-up: use the second one of the official regexps --- .../jetbrains/yaml/schema/YamlGenericValueAdapter.java | 2 +- .../yaml/schema/YamlByJsonSchemaHighlightingTest.java | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java index d7b13c413833..cfb8341e4e23 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlGenericValueAdapter.java @@ -145,7 +145,7 @@ public class YamlGenericValueAdapter implements JsonValueAdapter { private static boolean isFloat(@NotNull String s) { if (INFS.contains(trimSign(s)) || NANS.contains(s)) return true; if (hasTag(s, "float")) return true; - return Pattern.matches("[-+]?[1-9](\\.[0-9]*[1-9])?([eE][-+]?[1-9][0-9]*)?", s); + return Pattern.matches("[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?", s); } @NotNull diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java index 3c47234d86d0..5f5a11693743 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java @@ -796,10 +796,17 @@ public class YamlByJsonSchemaHighlightingTest extends JsonSchemaHighlightingTest public void testTravisPythonVersion() throws Exception { @Language("JSON") String schema = FileUtil.loadFile(new File(getTestDataPath() + "/travis.schema.json")); doTest(schema, "python: 3.5"); // validates as 'number' - doTest(schema, "python: 3.50"); // validates as 'string' + doTest(schema, "python: 3.50"); // validates as 'number' + doTest(schema, "python: 3.50a"); // validates as 'string' doTest(schema, "python: null"); } + public void testTravisNode() throws Exception { + @Language("JSON") String schema = FileUtil.loadFile(new File(getTestDataPath() + "/travis.schema.json")); + doTest(schema, "node_js: \n" + + " - 2.10"); + } + public void testExpNumberNotation() throws Exception { doTest("{\n" + " \"properties\": {\n" + From d95031af81ca2f1792b0d7a19945409e547783a4 Mon Sep 17 00:00:00 2001 From: Alexandr Evstigneev Date: Mon, 4 Feb 2019 16:10:58 +0300 Subject: [PATCH 042/138] Renamed method to measureExecutionTime IDEA-CR-42681 --- .../autodetect/JavaAutoDetectIndentPerformanceTest.java | 6 +++--- .../daemon/impl/focusMode/FocusModePassFactory.java | 2 +- .../com/intellij/ide/startup/impl/StartupManagerImpl.java | 2 +- .../src/com/intellij/testFramework/CpuTimings.java | 2 +- platform/util/src/com/intellij/util/TimeoutUtil.java | 2 +- .../org/intellij/lang/xpath/xslt/XsltHighlightingTest.java | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java index 74e3c1417ea0..5e453bdee2c6 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/JavaAutoDetectIndentPerformanceTest.java @@ -42,9 +42,9 @@ public class JavaAutoDetectIndentPerformanceTest extends AbstractIndentAutoDetec public void testBigColdFile() { Ref ref = Ref.create(); - long fileLoadTime = TimeoutUtil.runAndGetExecutionTime(() -> configureByFile(getFileNameWithExtension())); + long fileLoadTime = TimeoutUtil.measureExecutionTime(() -> configureByFile(getFileNameWithExtension())); - long detectingTime = TimeoutUtil.runAndGetExecutionTime(() -> ref.set(detectIndentOptions())); + long detectingTime = TimeoutUtil.measureExecutionTime(() -> ref.set(detectIndentOptions())); double ratio = (double)detectingTime / fileLoadTime; if (ratio > 0.3) { TeamCityLogger.error("Detecting indent have taken too much time proportionally to file read time " + ratio); @@ -69,7 +69,7 @@ public class JavaAutoDetectIndentPerformanceTest extends AbstractIndentAutoDetec public void testBigOneLineFile() { configureByFile("oneLine.json"); - long time = TimeoutUtil.runAndGetExecutionTime(AbstractIndentAutoDetectionTest::detectIndentOptions); + long time = TimeoutUtil.measureExecutionTime(AbstractIndentAutoDetectionTest::detectIndentOptions); assertTrue(time < 40); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java index 9df9ed9b646e..5a024d7beb88 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/focusMode/FocusModePassFactory.java @@ -70,7 +70,7 @@ public class FocusModePassFactory implements TextEditorHighlightingPassFactory { @NotNull private static List calcFocusZones(@NotNull FocusModeProvider focusModeProvider, @NotNull PsiFile psiFile) { Ref> resultRef = Ref.create(); - long executionTime = TimeoutUtil.runAndGetExecutionTime(() -> resultRef.set(focusModeProvider.calcFocusZones(psiFile))); + long executionTime = TimeoutUtil.measureExecutionTime(() -> resultRef.set(focusModeProvider.calcFocusZones(psiFile))); if (executionTime > MAX_ALLOWED_TIME) { LOG.warn("Focus zones collecting took too long: " + executionTime + "ms; " + "Provider: " + focusModeProvider.getClass().getSimpleName() + "; " + diff --git a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java index fdcd1b8df7cf..d844fd40a028 100644 --- a/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java @@ -149,7 +149,7 @@ public class StartupManagerImpl extends StartupManagerEx { } private void logActivityDuration(AtomicBoolean uiFreezeWarned, StartupActivity extension) { - long duration = TimeoutUtil.runAndGetExecutionTime(() -> extension.runActivity(myProject)); + long duration = TimeoutUtil.measureExecutionTime(() -> extension.runActivity(myProject)); Application app = ApplicationManager.getApplication(); if (duration > 100 && !app.isUnitTestMode()) { diff --git a/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java b/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java index 64ff7eff1161..5492805224ae 100644 --- a/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java +++ b/platform/testFramework/src/com/intellij/testFramework/CpuTimings.java @@ -38,7 +38,7 @@ class CpuTimings { StringBuilder log = new StringBuilder(); for (int i = 0;; i++) { - long time = TimeoutUtil.runAndGetExecutionTime(CpuTimings::addBigIntegers); + long time = TimeoutUtil.measureExecutionTime(CpuTimings::addBigIntegers); if (time < minTime) { //log.append("Iteration " + i + ", time " + time + "\n"); minTime = time; diff --git a/platform/util/src/com/intellij/util/TimeoutUtil.java b/platform/util/src/com/intellij/util/TimeoutUtil.java index 049b9e452192..0c8f4d17f332 100644 --- a/platform/util/src/com/intellij/util/TimeoutUtil.java +++ b/platform/util/src/com/intellij/util/TimeoutUtil.java @@ -69,7 +69,7 @@ public final class TimeoutUtil { * @return time of running {@code runnable} in milliseconds */ @ApiStatus.Experimental - public static long runAndGetExecutionTime(@NotNull ThrowableRunnable runnable) throws E { + public static long measureExecutionTime(@NotNull ThrowableRunnable runnable) throws E { long startTime = System.currentTimeMillis(); runnable.run(); return System.currentTimeMillis() - startTime; diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java index 0c537bc7bde1..4cc757854c31 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltHighlightingTest.java @@ -130,7 +130,7 @@ public class XsltHighlightingTest extends TestBase { final Project project = myFixture.getProject(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - return TimeoutUtil.runAndGetExecutionTime(() -> ReadAction.run( + return TimeoutUtil.measureExecutionTime(() -> ReadAction.run( () -> CodeInsightTestFixtureImpl.instantiateAndRun(myFixture.getFile(), myFixture.getEditor(), ArrayUtil.EMPTY_INT_ARRAY, false))); } From d928f2527b54f41799b914fcb804a5894b43bf27 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Feb 2019 12:16:58 +0100 Subject: [PATCH 043/138] a way to cancel or wait for all NonBlockingReadAction-s in tests cancel when a test is finished (and in tests disabling app events: IJI-110) wait in tests that need their result now --- .../impl/NonBlockingReadActionImpl.java | 59 ++++++++++++++++++- .../impl/text/AsyncHighlighterUpdater.java | 26 +------- .../application/impl/ApplicationImplTest.java | 1 + .../testFramework/PlatformTestCase.java | 4 +- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java index eb12721dbf71..600357a2cd61 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/NonBlockingReadActionImpl.java @@ -1,9 +1,12 @@ // 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.openapi.application.impl; +import com.google.common.annotations.VisibleForTesting; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.NonBlockingReadAction; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -12,26 +15,35 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.util.concurrency.Semaphore; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.concurrency.AsyncPromise; import org.jetbrains.concurrency.CancellablePromise; import org.jetbrains.concurrency.Promises; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BooleanSupplier; import java.util.function.Consumer; /** * @author peter */ -class NonBlockingReadActionImpl implements NonBlockingReadAction { +@VisibleForTesting +public class NonBlockingReadActionImpl implements NonBlockingReadAction { private final @Nullable Pair> myEdtFinish; private final @Nullable DumbService myRequireSmartMode; //todo a more pluggable constraint API private final BooleanSupplier myExpireCondition; private final Callable myComputation; + private static final Set> ourTasks = ContainerUtil.newConcurrentSet(); + NonBlockingReadActionImpl(@Nullable Pair> edtFinish, @Nullable DumbService requireSmartMode, @NotNull BooleanSupplier expireCondition, @@ -61,6 +73,10 @@ class NonBlockingReadActionImpl implements NonBlockingReadAction { public CancellablePromise submit(@NotNull Executor backgroundThreadExecutor) { AsyncPromise promise = new AsyncPromise<>(); new Submission(promise, backgroundThreadExecutor).transferToBgThread(); + if (ApplicationManager.getApplication().isUnitTestMode()) { + ourTasks.add(promise); + promise.onProcessed(__ -> ourTasks.remove(promise)); + } return promise; } @@ -167,4 +183,45 @@ class NonBlockingReadActionImpl implements NonBlockingReadAction { } } + + @TestOnly + public static void cancelAllTasks() { + while (!ourTasks.isEmpty()) { + for (CancellablePromise task : ourTasks) { + task.cancel(); + } + WriteAction.run(() -> {}); // let background threads complete + } + } + + @TestOnly + public static void completeAsyncTasks() { + assert !ApplicationManager.getApplication().isWriteAccessAllowed(); + for (CancellablePromise task : ourTasks) { + waitForTask(task); + } + } + + @TestOnly + private static void waitForTask(CancellablePromise task) { + int iteration = 0; + while (!task.isDone() && iteration++ < 60_000) { + UIUtil.dispatchAllInvocationEvents(); + try { + task.blockingGet(1, TimeUnit.MILLISECONDS); + return; + } + catch (TimeoutException ignore) { + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + if (!task.isDone()) { + //noinspection UseOfSystemOutOrSystemErr + System.err.println(ThreadDumper.dumpThreadsToString()); + throw new AssertionError("Too long async task"); + } + } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java index 60d28f761ffc..cbc02bf87f34 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncHighlighterUpdater.java @@ -15,9 +15,9 @@ */ package com.intellij.openapi.fileEditor.impl.text; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.EditorHighlighter; @@ -26,15 +26,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import org.jetbrains.concurrency.CancellablePromise; import java.util.Map; import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * @author peter @@ -66,26 +63,7 @@ public class AsyncHighlighterUpdater { @TestOnly public static void completeAsyncTasks() { - assert !ApplicationManager.getApplication().isWriteAccessAllowed(); - ApplicationManager.getApplication().invokeAndWait(() -> ourHighlighterFutures.values().forEach(AsyncHighlighterUpdater::waitForFuture)); - UIUtil.dispatchAllInvocationEvents(); + NonBlockingReadActionImpl.completeAsyncTasks(); } - @TestOnly - private static void waitForFuture(CancellablePromise future) { - int iteration = 0; - while (!future.isDone() && iteration++ < 1000) { - UIUtil.dispatchAllInvocationEvents(); - try { - future.blockingGet(10, TimeUnit.MILLISECONDS); - return; - } - catch (TimeoutException ignore) { - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - assert future.isDone() : "Too long async highlighter"; - } } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java index 48cf16a978d2..0024e9c8feff 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/application/impl/ApplicationImplTest.java @@ -135,6 +135,7 @@ public class ApplicationImplTest extends LightPlatformTestCase { } private static void runReadWrites(final int readIterations, final int writeIterations, int expectedMs) { + NonBlockingReadActionImpl.cancelAllTasks(); // someone might've submitted a task depending on app events which we disable now final ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication(); Disposable disposable = Disposer.newDisposable(); application.disableEventsUntil(disposable); diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 773f58a05ef3..cf375580d16e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -17,6 +17,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.application.impl.LaterInvocator; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.impl.DocumentReferenceManagerImpl; @@ -24,7 +25,6 @@ import com.intellij.openapi.command.impl.UndoManagerImpl; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.impl.text.AsyncHighlighterUpdater; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl; import com.intellij.openapi.module.EmptyModuleType; @@ -458,7 +458,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro ((PsiManagerImpl)PsiManager.getInstance(defaultProject)).cleanupForNextTest(); } - AsyncHighlighterUpdater.completeAsyncTasks(); + NonBlockingReadActionImpl.cancelAllTasks(); ((FileBasedIndexImpl) FileBasedIndex.getInstance()).cleanupForNextTest(); From 95d8cee02ea6a8afd2a369aa69e67a9dfcb793ae Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Thu, 31 Jan 2019 09:19:20 +0300 Subject: [PATCH 044/138] OC-18271 move IoTestUtil to `intellij.platform.testFramework` --- .../src}/com/intellij/openapi/util/io/IoTestUtil.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename platform/{util/testSrc => testFramework/src}/com/intellij/openapi/util/io/IoTestUtil.java (100%) diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java b/platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java similarity index 100% rename from platform/util/testSrc/com/intellij/openapi/util/io/IoTestUtil.java rename to platform/testFramework/src/com/intellij/openapi/util/io/IoTestUtil.java From 87a82c859382d10bd09e0db3cf30e6fbd0df6327 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Wed, 23 Jan 2019 15:16:20 +0300 Subject: [PATCH 045/138] OC-18271 "intellij.platform.testExtensions": make it production source root --- .../intellij.platform.testExtensions.iml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/platform/testFramework/extensions/intellij.platform.testExtensions.iml b/platform/testFramework/extensions/intellij.platform.testExtensions.iml index de1623e22634..3b0b46763fda 100644 --- a/platform/testFramework/extensions/intellij.platform.testExtensions.iml +++ b/platform/testFramework/extensions/intellij.platform.testExtensions.iml @@ -3,16 +3,16 @@ - + - - - - - - - + + + + + + + \ No newline at end of file From e01afe9f316b1c82847325077757556aa3517010 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Tue, 22 Jan 2019 19:18:05 +0300 Subject: [PATCH 046/138] OC-18271 introduce "intellij.platform.debugger.testFramework" module We need to move test API to a production source root to make it available to test API of "intellij.cidr.common.tests". see "CidrDebuggingFixture" class --- .../intellij.platform.scriptDebugger.ui.iml | 1 + .../intellij.platform.debugger.impl.iml | 5 ++--- .../intellij.platform.debugger.testFramework.iml | 15 +++++++++++++++ .../com/intellij/xdebugger/XDebuggerTestUtil.java | 0 .../intellij/xdebugger/XTestCompositeNode.java | 0 .../com/intellij/xdebugger/XTestContainer.java | 0 .../xdebugger/XTestEvaluationCallback.java | 0 .../com/intellij/xdebugger/XTestValueNode.java | 0 .../testSrc/intellij.python.community.tests.iml | 1 + 9 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml rename platform/{xdebugger-impl/testSrc => xdebugger-testFramework/src}/com/intellij/xdebugger/XDebuggerTestUtil.java (100%) rename platform/{xdebugger-impl/testSrc => xdebugger-testFramework/src}/com/intellij/xdebugger/XTestCompositeNode.java (100%) rename platform/{xdebugger-impl/testSrc => xdebugger-testFramework/src}/com/intellij/xdebugger/XTestContainer.java (100%) rename platform/{xdebugger-impl/testSrc => xdebugger-testFramework/src}/com/intellij/xdebugger/XTestEvaluationCallback.java (100%) rename platform/{xdebugger-impl/testSrc => xdebugger-testFramework/src}/com/intellij/xdebugger/XTestValueNode.java (100%) diff --git a/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml b/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml index 663770e03d59..1011e9c03742 100644 --- a/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml +++ b/platform/script-debugger/debugger-ui/intellij.platform.scriptDebugger.ui.iml @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/platform/xdebugger-impl/intellij.platform.debugger.impl.iml b/platform/xdebugger-impl/intellij.platform.debugger.impl.iml index 1a47d189939a..07dbdba41cbb 100644 --- a/platform/xdebugger-impl/intellij.platform.debugger.impl.iml +++ b/platform/xdebugger-impl/intellij.platform.debugger.impl.iml @@ -10,11 +10,10 @@ - - - + + \ No newline at end of file diff --git a/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml b/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml new file mode 100644 index 000000000000..99d0862410e0 --- /dev/null +++ b/platform/xdebugger-testFramework/intellij.platform.debugger.testFramework.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XDebuggerTestUtil.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XDebuggerTestUtil.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestCompositeNode.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestCompositeNode.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestCompositeNode.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestCompositeNode.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestContainer.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestContainer.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestEvaluationCallback.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestEvaluationCallback.java diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java b/platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestValueNode.java similarity index 100% rename from platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java rename to platform/xdebugger-testFramework/src/com/intellij/xdebugger/XTestValueNode.java diff --git a/python/testSrc/intellij.python.community.tests.iml b/python/testSrc/intellij.python.community.tests.iml index 8c6872662cd6..3d4533f4976f 100644 --- a/python/testSrc/intellij.python.community.tests.iml +++ b/python/testSrc/intellij.python.community.tests.iml @@ -28,5 +28,6 @@ + \ No newline at end of file From 24f1d986c1f451ac03749d6231d93215d09c3b38 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 4 Feb 2019 16:38:46 +0300 Subject: [PATCH 047/138] Gradle: allow to send custom test events for Gradle test runner using internal xml protocol --- .../gradle/tooling/builder/ExternalProjectBuilderImpl.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy index dd39b4b7cb69..93081ca212a6 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -157,7 +157,8 @@ class ExternalProjectBuilderImpl implements ModelBuilderService { externalTask.QName = task.name externalTask.description = task.description externalTask.group = task.group ?: "other" - externalTask.test = task instanceof Test + def ext = task.getExtensions()?.extraProperties + externalTask.test = (task instanceof Test) || (ext?.has("idea.internal.test") && ext.get("idea.internal.test") == true) externalTask.type = ProjectExtensionsDataBuilderImpl.getType(task) result.put(externalTask.name, externalTask) } From e2b18e112356d8b464f47680f0e05793cc9afa42 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Feb 2019 14:56:39 +0100 Subject: [PATCH 048/138] [vfs] reads symlink targets during refresh (IDEA-202236) --- .../com/intellij/java/index/IndexTest.groovy | 40 +++++----- .../vfs/newvfs/events/VFileCreateEvent.java | 8 ++ .../vfs/newvfs/impl/VirtualDirectoryImpl.java | 3 +- .../LocalFileSystemRefreshWorker.java | 6 +- .../newvfs/persistent/PersistentFSImpl.java | 35 +++++---- .../vfs/newvfs/persistent/RefreshWorker.java | 75 ++++++++++++------- .../persistent/VfsEventGenerationHelper.java | 8 +- .../openapi/vfs/VfsUtilLightTest.java | 6 +- .../openapi/vfs/VfsUtilPerformanceTest.java | 22 +----- .../vfs/impl/VirtualFilePointerRootsTest.java | 4 +- .../newvfs/persistent/PersistentFsTest.java | 24 +++--- 11 files changed, 128 insertions(+), 103 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy index e429ae6f0868..9c87b7ff5e37 100644 --- a/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/index/IndexTest.groovy @@ -1,4 +1,4 @@ -// 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-2019 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.java.index import com.intellij.ide.todo.TodoConfiguration @@ -154,7 +154,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VfsAwareMapIndexStorage indexStorage = new VfsAwareMapIndexStorage(storageFile, keyDescriptor, new EnumeratorStringDescriptor(), 16 * 1024, readOnly) return new StringIndex(testName, indexStorage, index, !readOnly) } - + private static PersistentHashMap> createMetaIndex(File metaIndexFile) throws IOException { return new PersistentHashMap>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer>() { @Override @@ -250,7 +250,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VirtualFile vFile = psiFile.getVirtualFile() CodeStyleManager.getInstance(project).reformat(psiFile) - + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting() PsiManager.getInstance(project).reloadFromDisk(psiFile) @@ -258,9 +258,9 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { def provider = PsiManager.getInstance(project).findViewProvider(vFile) def stubTree = ((PsiFileImpl)provider.getPsi(provider.getBaseLanguage())).getGreenStubTree() - + VfsUtil.saveText(vFile, "class Bar {}") - + assertNotNull(findClass("Foo")) } @@ -417,14 +417,14 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { GCUtil.tryGcSoftlyReachableObjects() assert ((PsiJavaFile)getPsiManager().findFile(vFile)).importList.node } - + void "test unknown file type in stubs" () { def vFile = myFixture.addFileToProject("Foo.java", "").virtualFile final Document document = FileDocumentManager.getInstance().getDocument(vFile) document.setText("class Foo {}") - PsiDocumentManager.getInstance(project).commitAllDocuments() + PsiDocumentManager.getInstance(project).commitAllDocuments() assert findClass("Foo") - + vFile.rename(null, "Foo1") assert !findClass("Foo") } @@ -553,12 +553,12 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile() def classEntry = new IdIndexEntry("class", true) def findValueProcessor = { file, value -> file != vFile } as FileBasedIndex.ValueProcessor - + def projectScope = GlobalSearchScope.projectScope(project) def result = FileBasedIndex.instance.processValues(IdIndexImpl.NAME, classEntry, null, findValueProcessor, projectScope) assertFalse(result) - + final Document document = FileDocumentManager.getInstance().getDocument(vFile) document.setText("") PsiDocumentManager.getInstance(project).commitAllDocuments() @@ -593,7 +593,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { void "test internalErrorOfStubProcessingInvalidatesIndex"() throws IOException { final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile() - + assertTrue(findClass("Foo") != null) runFindClassStubIndexQueryThatProducesInvalidResult("Foo") @@ -625,7 +625,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { return false } } - + try { StubIndex.instance. @@ -642,8 +642,8 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { catch (AssertionError ignored) { // stub mismatch } - - try { + + try { StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_FQN, key, project, searchScope, PsiFile.class, processor) fail("Unexpected") @@ -893,7 +893,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { Document document = FileDocumentManager.getInstance().getDocument(srcFile.virtualFile) document.replaceString(0, document.getTextLength(), 'class B {}') assertNotNull(findClass('A')) - + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).doCommitWithoutReparse(document) assertNull(findClass("A")) @@ -918,7 +918,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { assert findClass("Foo") } - + void "test read-only index has read-only storages"() { def index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), true).getIndex() @@ -952,7 +952,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename, filename2, true)) eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename2, filename, true)) eventList.add(new VFileDeleteEvent(null, file, true)) - eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, true, false)) + eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, null, true, false)) } IndexedFilesListener indexedFilesListener = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector @@ -972,18 +972,18 @@ class IndexTest extends JavaCodeInsightFixtureTestCase { def projectScope = GlobalSearchScope.projectScope(project) assert !JavaOverridingMethodUtil.getOverridingMethodsIfCheapEnough(runnable.methods[0], projectScope, { true }).findFirst().present - assert StubIndex.instance.getElements(JavaStubIndexKeys.METHODS, 'run', project, projectScope, PsiMethod).empty + assert StubIndex.instance.getElements(JavaStubIndexKeys.METHODS, 'run', project, projectScope, PsiMethod).empty } void "test text todo indexing checks for cancellation"() { TodoPattern pattern = new TodoPattern("(x+x+)+y", TodoAttributesUtil.createDefault(), true) - + TodoPattern[] oldPatterns = TodoConfiguration.getInstance().getTodoPatterns() TodoPattern[] newPatterns = [pattern] TodoConfiguration.getInstance().setTodoPatterns(newPatterns) FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project)) myFixture.addFileToProject("Foo.txt", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") - + try { final CountDownLatch progressStarted = new CountDownLatch(1) final ProgressIndicatorBase progressIndicatorBase = new ProgressIndicatorBase() diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java index cee150857c9f..febb55431c8a 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileCreateEvent.java @@ -18,6 +18,7 @@ public class VFileCreateEvent extends VFileEvent { private final boolean myEmptyDirectory; @NotNull private final String myChildName; private final FileAttributes myAttributes; + private final String mySymlinkTarget; private VirtualFile myCreatedFile; public VFileCreateEvent(Object requestor, @@ -25,6 +26,7 @@ public class VFileCreateEvent extends VFileEvent { @NotNull String childName, boolean isDirectory, @Nullable("null means read from the created file") FileAttributes attributes, + @Nullable String symlinkTarget, boolean isFromRefresh, boolean isEmptyDirectory) { super(requestor, isFromRefresh); @@ -32,6 +34,7 @@ public class VFileCreateEvent extends VFileEvent { myParent = parent; myDirectory = isDirectory; myAttributes = attributes; + mySymlinkTarget = symlinkTarget; myEmptyDirectory = isEmptyDirectory; } @@ -61,6 +64,11 @@ public class VFileCreateEvent extends VFileEvent { return myAttributes; } + @Nullable + public String getSymlinkTarget() { + return mySymlinkTarget; + } + @NonNls @Override public String toString() { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index b659d65fabc6..a62ad55cd976 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -267,7 +267,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { final String realName = delegate.getCanonicallyCasedName(fake); boolean isDirectory = attributes.isDirectory(); boolean isEmptyDirectory = isDirectory && !delegate.hasChildren(fake); - final VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDirectory, attributes, true, isEmptyDirectory); + String symlinkTarget = attributes.isSymLink() ? delegate.resolveSymLink(fake) : null; + VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDirectory, attributes, symlinkTarget, true, isEmptyDirectory); RefreshQueue.getInstance().processSingleEvent(event); return findChild(realName); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java index 5644b19c73ab..323e722089e4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/LocalFileSystemRefreshWorker.java @@ -272,7 +272,8 @@ class LocalFileSystemRefreshWorker { if (child == null) { // new file is created VirtualFile parent = myFileOrDir.isDirectory() ? myFileOrDir : myFileOrDir.getParent(); - myHelper.scheduleCreation(parent, name, file, convert(file, attrs)); + String symlinkTarget = attrs.isSymbolicLink() ? file.toRealPath().toString() : null; + myHelper.scheduleCreation(parent, name, file, convert(file, attrs), symlinkTarget); return FileVisitResult.CONTINUE; } @@ -300,7 +301,8 @@ class LocalFileSystemRefreshWorker { oldIsSpecial != isSpecial) { // symlink or directory or special changed myHelper.scheduleDeletion(child); VirtualFile parent = myFileOrDir.isDirectory() ? myFileOrDir : myFileOrDir.getParent(); - myHelper.scheduleCreation(parent, child.getName(), file, convert(file, attrs)); + String symlinkTarget = isLink ? file.toRealPath().toString() : null; + myHelper.scheduleCreation(parent, child.getName(), file, convert(file, attrs), symlinkTarget); // ignore everything else child.markClean(); return FileVisitResult.CONTINUE; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 5c93444f3d59..2324bb3224d3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -179,7 +179,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis nameIds.add(nameId); } for (String newName : toAdd) { - Pair childData = getChildData(null, file, newName, fs); + Pair childData = getChildData(fs, file, newName, null, null); if (childData != null) { int childId = makeChildRecord(id, newName, childData, fs); childrenIds.add(childId); @@ -387,7 +387,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis if (namesEqual(fs, childName, FSRecords.getNameSequence(childId))) return childId; } - Pair childData = getChildData(null, parent, childName, fs); + Pair childData = getChildData(fs, parent, childName, null, null); if (childData != null) { int childId = makeChildRecord(parentId, childName, childData, fs); FSRecords.updateList(parentId, ArrayUtil.append(children, childId)); @@ -426,7 +426,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis @Override public VirtualFile createChildDirectory(Object requestor, @NotNull VirtualFile parent, @NotNull String dir) throws IOException { getDelegate(parent).createChildDirectory(requestor, parent, dir); - processEvent(new VFileCreateEvent(requestor, parent, dir, true, null, false, true)); + processEvent(new VFileCreateEvent(requestor, parent, dir, true, null, null, false, true)); final VirtualFile child = parent.findChild(dir); if (child == null) { @@ -439,7 +439,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis @Override public VirtualFile createChildFile(Object requestor, @NotNull VirtualFile parent, @NotNull String file) throws IOException { getDelegate(parent).createChildFile(requestor, parent, file); - processEvent(new VFileCreateEvent(requestor, parent, file, false, null, false, false)); + processEvent(new VFileCreateEvent(requestor, parent, file, false, null, null, false, false)); final VirtualFile child = parent.findChild(file); if (child == null) { @@ -967,7 +967,7 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis for (VFileCreateEvent createEvent : createEvents) { createEvent.resetCache(); String name = createEvent.getChildName(); - Pair childData = getChildData(createEvent.getAttributes(), parent, name, delegate); + Pair childData = getChildData(delegate, parent, name, createEvent.getAttributes(), createEvent.getSymlinkTarget()); if (childData != null) { int childId = makeChildRecord(parentId, name, childData, delegate); childrenAdded.add(new ChildInfo(childId, name, childData.first, createEvent.isEmptyDirectory())); @@ -1129,8 +1129,8 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis } try { if (event instanceof VFileCreateEvent) { - final VFileCreateEvent createEvent = (VFileCreateEvent)event; - executeCreateChild(createEvent.getParent(), createEvent.getChildName(), createEvent.getAttributes(), createEvent.isEmptyDirectory()); + VFileCreateEvent ce = (VFileCreateEvent)event; + executeCreateChild(ce.getParent(), ce.getChildName(), ce.getAttributes(), ce.getSymlinkTarget(), ce.isEmptyDirectory()); } else if (event instanceof VFileDeleteEvent) { final VFileDeleteEvent deleteEvent = (VFileDeleteEvent)event; @@ -1152,8 +1152,8 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis executeTouch(file, contentUpdateEvent.isFromRefresh(), contentUpdateEvent.getModificationStamp(), length, timestamp); } else if (event instanceof VFileCopyEvent) { - final VFileCopyEvent copyEvent = (VFileCopyEvent)event; - executeCreateChild(copyEvent.getNewParent(), copyEvent.getNewChildName(), null, copyEvent.getFile().getChildren().length == 0); + VFileCopyEvent ce = (VFileCopyEvent)event; + executeCreateChild(ce.getNewParent(), ce.getNewChildName(), null, null, ce.getFile().getChildren().length == 0); } else if (event instanceof VFileMoveEvent) { final VFileMoveEvent moveEvent = (VFileMoveEvent)event; @@ -1199,10 +1199,11 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis private void executeCreateChild(@NotNull VirtualFile parent, @NotNull String name, @Nullable FileAttributes attributes, + @Nullable String symlinkTarget, boolean isEmptyDirectory) { NewVirtualFileSystem delegate = getDelegate(parent); int parentId = getFileId(parent); - Pair childData = getChildData(attributes, parent, name, delegate); + Pair childData = getChildData(delegate, parent, name, attributes, symlinkTarget); if (childData != null) { int childId = makeChildRecord(parentId, name, childData, delegate); appendIdToParentList(parentId, childId); @@ -1224,14 +1225,16 @@ public class PersistentFSImpl extends PersistentFS implements BaseComponent, Dis return childId; } - private static Pair getChildData(@Nullable FileAttributes attributes, + private static Pair getChildData(@NotNull NewVirtualFileSystem fs, @NotNull VirtualFile parent, @NotNull String name, - @NotNull NewVirtualFileSystem fs) { - if (attributes == null) attributes = fs.getAttributes(new FakeVirtualFile(parent, name)); - if (attributes == null) return null; - String symlinkTarget = attributes.isSymLink() ? fs.resolveSymLink(new FakeVirtualFile(parent, name)) : null; - return pair(attributes, symlinkTarget); + @Nullable FileAttributes attributes, + @Nullable String symlinkTarget) { + if (attributes == null) { + attributes = fs.getAttributes(new FakeVirtualFile(parent, name)); + symlinkTarget = attributes != null && attributes.isSymLink() ? fs.resolveSymLink(new FakeVirtualFile(parent, name)) : null; + } + return attributes == null ? null : pair(attributes, symlinkTarget); } private static void appendIdToParentList(int parentId, int childId) { diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index eacc25467eb3..b48fbef968d5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -107,7 +107,7 @@ public class RefreshWorker { } NewVirtualFile parent = file.getParent(); - if (parent != null && checkAndScheduleFileTypeChange(parent, file, attributes)) { + if (parent != null && checkAndScheduleFileTypeChange(fs, parent, file, attributes)) { // ignore everything else file.markClean(); continue; @@ -164,10 +164,16 @@ public class RefreshWorker { OpenTHashSet actualNames = fs.isCaseSensitive() ? null : new OpenTHashSet<>(strategy, upToDateNames); if (LOG.isTraceEnabled()) LOG.trace("current=" + Arrays.toString(currentNames) + " +" + newNames + " -" + deletedNames); - List> addedMap = ContainerUtil.newArrayListWithCapacity(newNames.size()); + List newKids = ContainerUtil.newArrayListWithCapacity(newNames.size()); for (String name : newNames) { checkCancelled(dir); - addedMap.add(pair(name, fs.getAttributes(new FakeVirtualFile(dir, name)))); + NewChildRecord record = childRecord(fs, dir, name); + if (record != null) { + newKids.add(record); + } + else { + if (LOG.isTraceEnabled()) LOG.trace("[+] fs=" + fs + " dir=" + dir + " name=" + name); + } } List> updatedMap = ContainerUtil.newArrayListWithCapacity(children.length); @@ -191,22 +197,15 @@ public class RefreshWorker { } } - for (Pair pair : addedMap) { - String name = pair.first; - FileAttributes childAttributes = pair.second; - if (childAttributes != null) { - myHelper.scheduleCreation(dir, name, appendPath(dir.getPath(), name), childAttributes); - } - else { - if (LOG.isTraceEnabled()) LOG.trace("[+] fs=" + fs + " dir=" + dir + " name=" + name); - } + for (NewChildRecord record : newKids) { + myHelper.scheduleCreation(dir, record.name, record.path, record.attributes, record.symlinkTarget); } for (Pair pair : updatedMap) { VirtualFile child = pair.first; FileAttributes childAttributes = pair.second; if (childAttributes != null) { - checkAndScheduleChildRefresh(dir, child, childAttributes); + checkAndScheduleChildRefresh(fs, dir, child, childAttributes); checkAndScheduleFileNameChange(actualNames, child); } else { @@ -255,11 +254,14 @@ public class RefreshWorker { existingMap.add(pair(child, fs.getAttributes(child))); } - List> wantedMap = ContainerUtil.newArrayListWithCapacity(wanted.size()); + List newKids = ContainerUtil.newArrayListWithCapacity(wanted.size()); for (String name : wanted) { if (name.isEmpty()) continue; checkCancelled(dir); - wantedMap.add(pair(name, fs.getAttributes(new FakeVirtualFile(dir, name)))); + NewChildRecord record = childRecord(fs, dir, name); + if (record != null) { + newKids.add(record); + } } // generating events unless a directory was changed in between @@ -273,7 +275,7 @@ public class RefreshWorker { VirtualFile child = pair.first; FileAttributes childAttributes = pair.second; if (childAttributes != null) { - checkAndScheduleChildRefresh(dir, child, childAttributes); + checkAndScheduleChildRefresh(fs, dir, child, childAttributes); checkAndScheduleFileNameChange(actualNames, child); } else { @@ -281,12 +283,8 @@ public class RefreshWorker { } } - for (Pair pair : wantedMap) { - String name = pair.first; - FileAttributes childAttributes = pair.second; - if (childAttributes != null) { - myHelper.scheduleCreation(dir, name, appendPath(dir.getPath(), name), childAttributes); - } + for (NewChildRecord record : newKids) { + myHelper.scheduleCreation(dir, record.name, record.path, record.attributes, record.symlinkTarget); } return true; @@ -297,6 +295,28 @@ public class RefreshWorker { } } + private static class NewChildRecord { + final String name; + final Path path; + final FileAttributes attributes; + final String symlinkTarget; + + NewChildRecord(String name, Path path, FileAttributes attributes, String symlinkTarget) { + this.name = name; + this.path = path; + this.attributes = attributes; + this.symlinkTarget = symlinkTarget; + } + } + + private static NewChildRecord childRecord(NewVirtualFileSystem fs, VirtualFile dir, String name) { + FakeVirtualFile file = new FakeVirtualFile(dir, name); + FileAttributes attributes = fs.getAttributes(file); + if (attributes == null) return null; + String symlinkTarget = attributes.isSymLink() ? fs.resolveSymLink(file) : null; + return new NewChildRecord(name, appendPath(dir.getPath(), name), attributes, symlinkTarget); + } + private void checkAndScheduleFileNameChange(@Nullable OpenTHashSet actualNames, @NotNull VirtualFile child) { if (actualNames != null) { String currentName = child.getName(); @@ -327,10 +347,11 @@ public class RefreshWorker { file.markDirty(); } - private void checkAndScheduleChildRefresh(@NotNull VirtualFile parent, + private void checkAndScheduleChildRefresh(NewVirtualFileSystem fs, + @NotNull VirtualFile parent, @NotNull VirtualFile child, @NotNull FileAttributes childAttributes) { - if (!checkAndScheduleFileTypeChange(parent, child, childAttributes)) { + if (!checkAndScheduleFileTypeChange(fs, parent, child, childAttributes)) { boolean upToDateIsDirectory = childAttributes.isDirectory(); if (myIsRecursive || !upToDateIsDirectory) { myRefreshQueue.addLast(pair((NewVirtualFile)child, childAttributes)); @@ -338,7 +359,8 @@ public class RefreshWorker { } } - private boolean checkAndScheduleFileTypeChange(@NotNull VirtualFile parent, + private boolean checkAndScheduleFileTypeChange(NewVirtualFileSystem fs, + @NotNull VirtualFile parent, @NotNull VirtualFile child, @NotNull FileAttributes childAttributes) { boolean currentIsDirectory = child.isDirectory(); @@ -350,7 +372,8 @@ public class RefreshWorker { if (currentIsDirectory != upToDateIsDirectory || currentIsSymlink != upToDateIsSymlink || currentIsSpecial != upToDateIsSpecial) { myHelper.scheduleDeletion(child); - myHelper.scheduleCreation(parent, child.getName(), appendPath(parent.getPath(), child.getName()), childAttributes); + String symlinkTarget = upToDateIsSymlink ? fs.resolveSymLink(child) : null; + myHelper.scheduleCreation(parent, child.getName(), appendPath(parent.getPath(), child.getName()), childAttributes, symlinkTarget); return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java index 4e8c8d6d130b..a09a11a6b9b4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VfsEventGenerationHelper.java @@ -46,11 +46,15 @@ class VfsEventGenerationHelper { myEvents.add(new VFileContentChangeEvent(null, file, file.getModificationStamp(), -1, oldTimestamp, newTimestamp, oldLength, newLength, true)); } - void scheduleCreation(@NotNull VirtualFile parent, @NotNull String childName, @NotNull Path path, @NotNull FileAttributes attributes) { + void scheduleCreation(@NotNull VirtualFile parent, + @NotNull String childName, + @NotNull Path path, + @NotNull FileAttributes attributes, + String symlinkTarget) { boolean isEmptyDir = attributes.isDirectory() && !LocalFileSystemBase.hasChildren(path); if (LOG.isTraceEnabled()) LOG.trace("create parent=" + parent + " name=" + childName + " attr=" + attributes); - myEvents.add(new VFileCreateEvent(null, parent, childName, attributes.isDirectory(), attributes, true, isEmptyDir)); + myEvents.add(new VFileCreateEvent(null, parent, childName, attributes.isDirectory(), attributes, symlinkTarget, true, isEmptyDir)); } void scheduleDeletion(@NotNull VirtualFile file) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java index 890de4636846..6e0d1a40c732 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilLightTest.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-2019 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.openapi.vfs; import com.intellij.openapi.util.io.FileUtil; @@ -64,7 +62,7 @@ public class VfsUtilLightTest extends BareTestFixtureTestCase { VirtualFile jarRoot = VirtualFileManager.getInstance().findFileByUrl("jar://" + FileUtil.toSystemIndependentName(jarFile.getPath()) + "!/"); assertNotNull(jarRoot); - VFileCreateEvent event = new VFileCreateEvent(this, jarRoot, "x.txt", false, null, false, false); + VFileCreateEvent event = new VFileCreateEvent(this, jarRoot, "x.txt", false, null, null, false, false); assertEquals(FileUtil.toSystemIndependentName(jarFile.getPath()) + "!/x.txt", event.getPath()); } } \ No newline at end of file diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java index e79f9378c94f..381b4821d719 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/VfsUtilPerformanceTest.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2016 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-2019 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.openapi.vfs; import com.intellij.concurrency.JobLauncher; @@ -105,7 +91,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { NewVirtualFile root = ManagingFS.getInstance().findRoot(path, fs); PlatformTestUtil.startPerformanceTest("finding root", 10_000, () -> JobLauncher.getInstance().invokeConcurrentlyUnderProgress( - Collections.nCopies(500, null), null, + Collections.nCopies(500, null), null, __ -> { for (int i = 0; i < 20_000; i++) { NewVirtualFile rootJar = ManagingFS.getInstance().findRoot(path, fs); @@ -194,7 +180,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { public void testAsyncRefresh() throws Throwable { Ref ex = Ref.create(); boolean success = JobLauncher.getInstance().invokeConcurrentlyUnderProgress( - Arrays.asList(new Object[JobSchedulerImpl.getJobPoolParallelism()]), ProgressManager.getInstance().getProgressIndicator(), + Arrays.asList(new Object[JobSchedulerImpl.getJobPoolParallelism()]), ProgressManager.getInstance().getProgressIndicator(), o -> { try { doAsyncRefreshTest(); @@ -332,7 +318,7 @@ public class VfsUtilPerformanceTest extends BareTestFixtureTestCase { events.clear(); TempFileSystem fs = TempFileSystem.getInstance(); IntStream.range(0, N) - .mapToObj(i -> new VFileCreateEvent(this, temp, i + ".txt", false, null, false, false)) + .mapToObj(i -> new VFileCreateEvent(this, temp, i + ".txt", false, null, null, false, false)) .peek(event -> { if (fs.findModelChild(temp, event.getChildName()) == null) { fs.createChildFile(this, temp, event.getChildName()); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java index 5686d55e0d62..d87c27e01278 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/impl/VirtualFilePointerRootsTest.java @@ -1,4 +1,4 @@ -// 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-2019 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.openapi.vfs.impl; import com.intellij.openapi.Disposable; @@ -92,7 +92,7 @@ public class VirtualFilePointerRootsTest extends PlatformTestCase { myVirtualFilePointerManager.shelveAllPointersIn(() -> { for (int i = 0; i < 100_000; i++) { myVirtualFilePointerManager.create(VfsUtilCore.pathToUrl("/a/b/c/d/" + i), disposable, listener); - events.add(new VFileCreateEvent(this, temp, "xxx" + i, false, null, true, false)); + events.add(new VFileCreateEvent(this, temp, "xxx" + i, false, null, null, true, false)); } PlatformTestUtil.startPerformanceTest("vfp update", 7_000, () -> { for (int i = 0; i < 100; i++) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java index 604a03c3f48a..95cad6a2713d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/newvfs/persistent/PersistentFsTest.java @@ -1,4 +1,4 @@ -// 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-2019 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.openapi.vfs.newvfs.persistent; import com.intellij.openapi.Disposable; @@ -197,11 +197,11 @@ public class PersistentFsTest extends PlatformTestCase { // wrt persistence subDir becomes partially loaded and subsubDir becomes fully loaded File nestedDirOutsideTheProject = new File(projectStructure.getPath() + "../../../"+testName + "/subDir", "subSubDir").getCanonicalFile(); Disposable disposable = null; - + try { boolean atleastSecondRun = nestedDirOutsideTheProject.getParentFile().getParentFile().exists(); StringBuilder eventLog = new StringBuilder(); - + if (atleastSecondRun) { disposable = Disposer.newDisposable(); getProject().getMessageBus().connect(disposable).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @@ -219,18 +219,18 @@ public class PersistentFsTest extends PlatformTestCase { } }); } - + // recreating structure will fire vfs removal events VirtualFile nestedDirOutsideTheProjectFile = VfsUtil.createDirectories(nestedDirOutsideTheProject.getPath()); WriteAction.run(() -> nestedDirOutsideTheProjectFile.createChildData(null, "Foo.txt")); - + // subsubDir becomes fully loaded wrt persistence nestedDirOutsideTheProjectFile.getChildren(); if (atleastSecondRun) { - assertEquals("subDir\n" + + assertEquals("subDir\n" + "subDir/subSubDir\n" + - "subDir/subSubDir/Foo.txt\n", + "subDir/subSubDir/Foo.txt\n", eventLog.toString() ); } @@ -240,7 +240,7 @@ public class PersistentFsTest extends PlatformTestCase { FileUtil.delete(nestedDirOutsideTheProject.getParentFile()); } } - + public void testModCountIncreases() throws IOException { VirtualFile vFile = setupFile(); ManagingFS managingFS = ManagingFS.getInstance(); @@ -360,10 +360,10 @@ public class PersistentFsTest extends PlatformTestCase { checkEvents("Before:[VFileCreateEvent->xx.created, VFileDeleteEvent->file.txt]\n" + "After:[VFileCreateEvent->xx.created, VFileDeleteEvent->file.txt]\n", new VFileDeleteEvent(this, vFile, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, null, false, false), new VFileDeleteEvent(this, vFile, false)); } - + public void testProcessEventsMustGroupDependentEventsCorrectly2() throws IOException { File file = new File(createTempDirectory(), "a/b/c/test.txt"); assertTrue(file.getParentFile().mkdirs()); @@ -377,8 +377,8 @@ public class PersistentFsTest extends PlatformTestCase { "Before:[VFileDeleteEvent->c]\n" + "After:[VFileDeleteEvent->c]\n", new VFileDeleteEvent(this, vFile, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, false, false), - new VFileCreateEvent(this, vFile.getParent(), "xx.created2", false, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created", false, null, null, false, false), + new VFileCreateEvent(this, vFile.getParent(), "xx.created2", false, null, null, false, false), new VFileDeleteEvent(this, vFile.getParent(), false)); } From 64d3c71276a7a4a0a825dc830c3c6dbd758ffb5c Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 4 Feb 2019 17:04:10 +0300 Subject: [PATCH 049/138] Gradle: allow to send custom test events for Gradle test runner using internal xml protocol --- .../gradle/tooling/builder/ExternalProjectBuilderImpl.groovy | 2 +- .../plugins/gradle/tooling/internal/init/testFilterInit.gradle | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy index 93081ca212a6..c38c0c815e83 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -158,7 +158,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService { externalTask.description = task.description externalTask.group = task.group ?: "other" def ext = task.getExtensions()?.extraProperties - externalTask.test = (task instanceof Test) || (ext?.has("idea.internal.test") && ext.get("idea.internal.test") == true) + externalTask.test = (task instanceof Test) || (ext?.has("idea.internal.test") && Boolean.valueOf(ext.get("idea.internal.test"))) externalTask.type = ProjectExtensionsDataBuilderImpl.getType(task) result.put(externalTask.name, externalTask) } diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/testFilterInit.gradle b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/testFilterInit.gradle index 174db92e3b64..51a5e201ab14 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/testFilterInit.gradle +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/internal/init/testFilterInit.gradle @@ -3,6 +3,7 @@ import groovy.xml.MarkupBuilder import org.gradle.api.internal.tasks.testing.TestDescriptorInternal import org.gradle.util.* +System.setProperty("idea.active", "true") String[] ijTestIncludes = ${TEST_NAME_INCLUDES} boolean ijTestFilteringSupported = GradleVersion.current().compareTo(GradleVersion.version("1.10"))>=0 boolean skipExecution From e00ecc9156e35c29481efe3ff0005b3bdc3da424 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Feb 2019 14:54:59 +0300 Subject: [PATCH 050/138] Java: Shortened text messages for highlighting of duplicate values and branches in enhanced 'switch' (IDEA-202629) --- .../DuplicateBranchesInSwitchInspection.java | 86 ++++--------------- .../CaseLabelsExpression.java | 2 +- .../CaseLabelsExpressionDefaultFirst.java | 2 +- .../CaseLabelsExpressionDefaultLast.java | 2 +- .../CaseLabelsExpressionSameComments.java | 2 +- .../ExpressionParentheses.java | 2 +- .../ReturnInStatement.java | 2 +- .../SimpleExpression.java | 2 +- .../SimpleStatement.java | 2 +- .../StatementParentheses.java | 2 +- .../ThrowInExpression.java | 2 +- .../ThrowInStatement.java | 2 +- ...ExpressionDuplicateAfterDefaultDelete.java | 2 +- ...xpressionDuplicateBeforeDefaultDelete.java | 2 +- ...nDuplicateBeforeDefaultDeleteAdjacent.java | 2 +- ...ExpressionDuplicateAfterDefaultDelete.java | 2 +- ...xpressionDuplicateBeforeDefaultDelete.java | 2 +- ...nDuplicateBeforeDefaultDeleteAdjacent.java | 2 +- .../duplicateBranchesInSwitch/Assignment.java | 4 +- .../BreakAndReturnUnderIf.java | 2 +- .../ComplexBranches.java | 2 +- .../duplicateBranchesInSwitch/Continue.java | 2 +- .../DuplicateAfterDefault.java | 2 +- .../FallThroughToBreak.java | 4 +- .../ManySimilarBranches.java | 62 ++++++------- .../MethodCallInReturn.java | 4 +- .../NoLastBreak.java | 2 +- .../Parentheses.java | 2 +- .../duplicateBranchesInSwitch/Return.java | 2 +- .../ReturnWithComments.java | 12 +-- .../duplicateBranchesInSwitch/Simple.java | 2 +- .../ThreeDuplicates.java | 4 +- .../ThreeDuplicatesDefault.java | 4 +- .../duplicateBranchesInSwitch/Throw.java | 2 +- .../TwoCaseLabels.java | 2 +- .../DuplicateBranchesInSwitchSuite.java | 1 + .../src/messages/InspectionsBundle.properties | 21 ++--- 37 files changed, 98 insertions(+), 158 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java index c69c35555266..813ccbef05d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java @@ -275,27 +275,23 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { private static class MergeBranchesFix implements LocalQuickFix { @NotNull private final String mySwitchLabelText; - private final boolean myInExpression; - MergeBranchesFix(@NotNull String switchLabelText, boolean inExpression) { + MergeBranchesFix(@NotNull String switchLabelText) { mySwitchLabelText = switchLabelText; - myInExpression = inExpression; } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.family.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.name", mySwitchLabelText); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.name", mySwitchLabelText); } @Override @@ -329,26 +325,19 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class DeleteRedundantBranchFix implements LocalQuickFix { - private final boolean myInExpression; - - private DeleteRedundantBranchFix(boolean inExpression) { - myInExpression = inExpression; - } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.family.name"); } @Override @@ -538,15 +527,11 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } String getCaseBranchMessage() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.statement.message"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.message"); } String getDefaultBranchMessage() { - return myInExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.default.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.statement.default.message"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.default.message"); } @Override @@ -681,7 +666,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newMergeCasesFix() { String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeBranchesFix(switchLabelText, myInExpression) : null; + return switchLabelText != null ? new MergeBranchesFix(switchLabelText) : null; } @Override @@ -691,7 +676,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantBranchFix(myInExpression); + return new DeleteRedundantBranchFix(); } /** @@ -798,7 +783,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class Rule extends BranchBase { - private final boolean myIsResult; private final boolean myIsSimpleExit; Rule(@NotNull PsiSwitchLabeledRuleStatement rule, @NotNull PsiStatement body, @NotNull String[] commentTexts) { @@ -806,7 +790,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { new PsiStatement[]{body}, commentTexts); - myIsResult = body instanceof PsiExpressionStatement; myIsSimpleExit = body instanceof PsiExpressionStatement || body instanceof PsiThrowStatement; } @@ -820,31 +803,11 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { return false; } - @Override - String getCaseBranchMessage() { - if (myInExpression) { - return myIsResult - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.result.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.message"); - } - return super.getCaseBranchMessage(); - } - - @Override - String getDefaultBranchMessage() { - if (myInExpression) { - return myIsResult - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.default.result.message") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.default.message"); - } - return super.getDefaultBranchMessage(); - } - @Nullable @Override LocalQuickFix newMergeCasesFix() { String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeRulesFix(switchLabelText, isResultExpression()) : null; + return switchLabelText != null ? new MergeRulesFix(switchLabelText) : null; } @Override @@ -854,37 +817,29 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantRuleFix(isResultExpression()); - } - - private boolean isResultExpression() { - return myInExpression && myIsResult; + return new DeleteRedundantRuleFix(); } } private static class MergeRulesFix implements LocalQuickFix { @NotNull private final String mySwitchLabelText; - private final boolean myIsResultExpression; - MergeRulesFix(@NotNull String switchLabelText, boolean isResultExpression) { + MergeRulesFix(@NotNull String switchLabelText) { mySwitchLabelText = switchLabelText; - myIsResultExpression = isResultExpression; } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.family.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return InspectionsBundle.message("inspection.duplicate.branches.in.switch.fix.name", mySwitchLabelText); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.fix.name", mySwitchLabelText); } @Override @@ -898,28 +853,19 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } private static class DeleteRedundantRuleFix implements LocalQuickFix { - private final boolean myIsResultExpression; - - DeleteRedundantRuleFix(boolean isResultExpression) { - myIsResultExpression = isResultExpression; - } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.name"); } @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull @Override public String getFamilyName() { - return myIsResultExpression - ? InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name") - : InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.family.name"); + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.delete.fix.family.name"); } @Override diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java index 10ff237cbb71..df6d8b91435a 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpression.java @@ -6,7 +6,7 @@ class C { case 2: break "b"; case 3: - break "a"; + break "a"; default: break ""; }; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java index 1b86bbbf4335..d0ce32d5bda4 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultFirst.java @@ -7,7 +7,7 @@ class C { case 2: break "b"; case 3: - break "a"; + break "a"; }; } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java index 54d41a124d55..70f28327bfa1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionDefaultLast.java @@ -2,7 +2,7 @@ class C { void test(int n) { String s = switch (n) { case 1: - break "a"; + break "a"; case 2: break "b"; case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java index 34035a0a5294..5f55aff25d39 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/CaseLabelsExpressionSameComments.java @@ -6,7 +6,7 @@ class C { case 2: break "b"; case 3: - break "a"; // same comment + break "a"; // same comment default: break ""; }; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java index 8e28a3e704b0..6379f8db99a0 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ExpressionParentheses.java @@ -2,7 +2,7 @@ class C { String test(int i) { return switch (i) { case 0 -> null; - case 1 -> (null); + case 1 -> (null); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java index af3138baf412..5c40a31a9026 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ReturnInStatement.java @@ -3,7 +3,7 @@ class C { return switch (n) { case 1 -> "A"; case 2 -> "B"; - case 3 -> "A"; + case 3 -> "A"; default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java index 1f60738ff1b2..e8bfc5d9abe8 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleExpression.java @@ -3,7 +3,7 @@ class C { String string = switch (n) { case 1 -> bar("A"); case 2 -> bar("B"); - case 3 -> bar("A"); + case 3 -> bar("A"); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java index 948ef11901aa..f0d4cb5e9f8a 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/SimpleStatement.java @@ -3,7 +3,7 @@ class C { switch (n) { case 1 -> bar("A"); case 2 -> bar("B"); - case 3 -> bar("A"); + case 3 -> bar("A"); } } void bar(String s){} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java index 427560266afa..af89b19389e3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/StatementParentheses.java @@ -4,7 +4,7 @@ class C { case 0 ->{ return null; } - case 1 ->{ + case 1 ->{ return (null); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java index 9a1ecfc6f582..766681c413bd 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInExpression.java @@ -3,7 +3,7 @@ class C { String string = switch (n) { case 1 -> throw new IllegalArgumentException(); case 2 -> throw new IllegalStateException(); - case 3 -> throw new IllegalArgumentException(); + case 3 -> throw new IllegalArgumentException(); default -> ""; }; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java index c5c80b5c5d84..a07b0c5d6d1d 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/ThrowInStatement.java @@ -3,7 +3,7 @@ class C { switch (n) { case 1 -> throw new IllegalArgumentException(); case 2 -> throw new IllegalStateException(); - case 3 -> throw new IllegalArgumentException(); + case 3 -> throw new IllegalArgumentException(); } } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java index 3a7856ff93c0..42bce24c3bd4 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateAfterDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java index d778394d1bcd..5520fd47b87b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java index d778394d1bcd..5520fd47b87b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterExpressionDuplicateBeforeDefaultDeleteAdjacent.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java index c0d30dd573a3..485f96a6d9e6 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateAfterDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java index d0f4dde0acf3..a8545cf6b526 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDelete.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java index dfd840b71ced..b50d3e58a94b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeExpressionDuplicateBeforeDefaultDeleteAdjacent.java @@ -1,4 +1,4 @@ -// "Delete redundant 'switch' result expression" "GENERIC_ERROR_OR_WARNING" +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" class C { void foo(int n) { String s = switch (n) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java index 05e52111051d..0c17c5baed8c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Assignment.java @@ -3,8 +3,8 @@ class C { String s; switch (n) { case 0: s = a(); break; - case 1: s = a(); break; - case 2: s = b(); break; + case 1: s = a(); break; + case 2: s = b(); break; default: s = b(); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java index ab22f4bbd344..ef3591c58f85 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java @@ -14,7 +14,7 @@ class C { break; } case 3: - if(b) { + if(b) { return bar("A"); } else { break; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java index 1c33db404c4b..dd72ac35f3ad 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java @@ -18,7 +18,7 @@ class C { bar("o"); break; case 3: - if(b) { + if(b) { bar("A"); } else { bar("z"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java index 8b5f677511c1..596a5ced55ae 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java @@ -9,7 +9,7 @@ class C { case 2: continue; case 3: - s += i; + s += i; continue; default: s += i; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java index 2e11cf08416c..7b4749a7b9de 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java @@ -8,7 +8,7 @@ class C { bar("A"); break; case 1: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java index c4fcf393799b..344a1c5cf5fc 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java @@ -6,10 +6,10 @@ class C { case 2: break; case 3: - bar("A"); + bar("A"); break; case 4: - bar("A"); + bar("A"); case 5: } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java index a9837a19b235..cd99923bf985 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ManySimilarBranches.java @@ -13,7 +13,7 @@ class C { case 6: bar("F");break; case 7: bar("G");break; case 8: bar("H");break; - case 9: bar("A");break; + case 9: bar("A");break; case 11: return Collections.singletonMap(k + 1, Collections.singletonList("A")); case 12: return Collections.singletonMap(k + 2, Collections.singletonList("B")); @@ -23,7 +23,7 @@ class C { case 16: return Collections.singletonMap(k + 6, Collections.singletonList("F")); case 17: return Collections.singletonMap(k + 7, Collections.singletonList("G")); case 18: return Collections.singletonMap(k + 8, Collections.singletonList("H")); - case 19: return Collections.singletonMap(k + 1, Collections.singletonList("A")); + case 19: return Collections.singletonMap(k + 1, Collections.singletonList("A")); case 21: synchronized (lock) { bar("A"); }break; case 22: synchronized (lock) { bar("B"); }break; @@ -33,7 +33,7 @@ class C { case 26: synchronized (lock) { bar("F"); }break; case 27: synchronized (lock) { bar("G"); }break; case 28: synchronized (lock) { bar("H"); }break; - case 29: synchronized (lock) { bar("A"); }break; + case 29: synchronized (lock) { bar("A"); }break; case 31: assert k == 1;break; case 32: assert k == 2;break; @@ -43,36 +43,36 @@ class C { case 36: assert k == 6;break; case 37: assert k == 7;break; case 38: assert k == 8;break; - case 39: assert k == 1;break; + case 39: assert k == 1;break; case 41: if (k > 0) bar("A"); else bar("B");break; - case 42: if (k > 0) bar("A"); else bar("B");break; - case 43: if (k > 0) bar("A"); else bar("B");break; - case 44: if (k > 0) bar("A"); else bar("B");break; - case 45: if (k > 0) bar("A"); else bar("B");break; - case 46: if (k > 0) bar("A"); else bar("B");break; - case 47: if (k > 0) bar("A"); else bar("B");break; - case 48: if (k > 0) bar("A"); else bar("B");break; - case 49: if (k > 0) bar("A"); else bar("B");break; - case 50: if (k > 0) bar("A"); else bar("B");break; - case 51: if (k > 0) bar("A"); else bar("B");break; - case 52: if (k > 0) bar("A"); else bar("B");break; - case 53: if (k > 0) bar("A"); else bar("B");break; - case 54: if (k > 0) bar("A"); else bar("B");break; - case 55: if (k > 0) bar("A"); else bar("B");break; - case 56: if (k > 0) bar("A"); else bar("B");break; - case 57: if (k > 0) bar("A"); else bar("B");break; - case 58: if (k > 0) bar("A"); else bar("B");break; - case 59: if (k > 0) bar("A"); else bar("B");break; - case 61: if (k > 0) bar("A"); else bar("B");break; - case 62: if (k > 0) bar("A"); else bar("B");break; - case 63: if (k > 0) bar("A"); else bar("B");break; - case 64: if (k > 0) bar("A"); else bar("B");break; - case 65: if (k > 0) bar("A"); else bar("B");break; - case 66: if (k > 0) bar("A"); else bar("B");break; - case 67: if (k > 0) bar("A"); else bar("B");break; - case 68: if (k > 0) bar("A"); else bar("B");break; - case 69: if (k > 0) bar("A"); else bar("B");break; + case 42: if (k > 0) bar("A"); else bar("B");break; + case 43: if (k > 0) bar("A"); else bar("B");break; + case 44: if (k > 0) bar("A"); else bar("B");break; + case 45: if (k > 0) bar("A"); else bar("B");break; + case 46: if (k > 0) bar("A"); else bar("B");break; + case 47: if (k > 0) bar("A"); else bar("B");break; + case 48: if (k > 0) bar("A"); else bar("B");break; + case 49: if (k > 0) bar("A"); else bar("B");break; + case 50: if (k > 0) bar("A"); else bar("B");break; + case 51: if (k > 0) bar("A"); else bar("B");break; + case 52: if (k > 0) bar("A"); else bar("B");break; + case 53: if (k > 0) bar("A"); else bar("B");break; + case 54: if (k > 0) bar("A"); else bar("B");break; + case 55: if (k > 0) bar("A"); else bar("B");break; + case 56: if (k > 0) bar("A"); else bar("B");break; + case 57: if (k > 0) bar("A"); else bar("B");break; + case 58: if (k > 0) bar("A"); else bar("B");break; + case 59: if (k > 0) bar("A"); else bar("B");break; + case 61: if (k > 0) bar("A"); else bar("B");break; + case 62: if (k > 0) bar("A"); else bar("B");break; + case 63: if (k > 0) bar("A"); else bar("B");break; + case 64: if (k > 0) bar("A"); else bar("B");break; + case 65: if (k > 0) bar("A"); else bar("B");break; + case 66: if (k > 0) bar("A"); else bar("B");break; + case 67: if (k > 0) bar("A"); else bar("B");break; + case 68: if (k > 0) bar("A"); else bar("B");break; + case 69: if (k > 0) bar("A"); else bar("B");break; } return Collections.emptyMap(); } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java index 9b59d388f217..f304e97eb1e1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java @@ -7,10 +7,10 @@ enum T { return t.ordinal(); // comment 1 case B: - return t.ordinal(); + return t.ordinal(); case C: - return t.ordinal(); // comment 2 + return t.ordinal(); // comment 2 default: return 0; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java index ba5a9b985323..c80c007c19c6 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java @@ -8,7 +8,7 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); } } void bar(String s){} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java index 5ab056215787..566c8c3a01fc 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Parentheses.java @@ -2,7 +2,7 @@ class C { String test(int i) { switch (i) { case 0: return null; - case 1: return (null); + case 1: return (null); } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java index 279d6f216b5c..fc50633a268c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java @@ -6,7 +6,7 @@ class C { case 2: return "B"; case 3: - return "A"; + return "A"; } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java index c0cea839f630..3ba67727c6f3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java @@ -13,24 +13,24 @@ enum C { return "A"; case LINE_COMMENT: // comment 1 - return "A"; + return "A"; case COMMENT_INSIDE_THE_CODE: - return /* comment 1 */"A"; + return /* comment 1 */"A"; case JAVADOC_COMMENT: /** comment 1 */ - return "A"; + return "A"; case COMMENT_WITH_NEW_LINES: /* comment 1 */ - return "A"; + return "A"; case EMPTY_COMMENTS_ARE_IGNORED: /* comment 1 */ // - return "A"; + return "A"; // comment 1 case COMMENT_RIGHT_BEFORE_A_CASE_IS_ATTACHED_TO_THAT_CASE: - return "A"; + return "A"; } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java index 9ea8da8ad9c3..bb0c0275a31b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java @@ -8,7 +8,7 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java index a0f999f4ed9b..1f487f18d1e3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java @@ -8,10 +8,10 @@ class C { bar("B"); break; case 3: - bar("A"); + bar("A"); break; case 4: - bar("A"); + bar("A"); break; } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java index d5497c91382f..05af5fedc09c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java @@ -2,13 +2,13 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); break; case 2: bar("B"); break; case 3: - bar("A"); + bar("A"); break; default: bar("A"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java index 7021fa2adfd6..ac900caf94c8 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java @@ -6,7 +6,7 @@ class C { case 2: throw new IllegalStateException("A"); case 3: - throw new IllegalArgumentException("A"); + throw new IllegalArgumentException("A"); } return ""; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java index 3396a9fb2a53..09338258dd83 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java @@ -6,7 +6,7 @@ class C { bar("A"); break; case 3: - bar("A"); + bar("A"); break; case 4: bar("B"); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java index d15bb534e298..646408ff3b01 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchSuite.java @@ -5,6 +5,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; /** + * Tests for {@link com.intellij.codeInspection.DuplicateBranchesInSwitchInspection} * @author Pavel.Dolgov */ @RunWith(Suite.class) diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 8127a4b22da8..e5c5c55fca39 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -1051,20 +1051,13 @@ inspection.switch.expression.backward.expression.migration.inspection.name='swit inspection.switch.expression.backward.statement.migration.inspection.name='switch' statement can be replaced with old style 'switch' statement inspection.replace.with.old.style.switch.statement.fix.name=Replace with old style 'switch' statement -inspection.duplicate.branches.in.switch.display.name=Duplicate branches in 'switch' statement -inspection.duplicate.branches.in.switch.statement.message=Duplicate branch in 'switch' statement -inspection.duplicate.branches.in.switch.expression.message=Duplicate branch in 'switch' expression -inspection.duplicate.branches.in.switch.result.message=Duplicate result expression in 'switch' expression -inspection.duplicate.branches.in.switch.statement.default.message=Branch in 'switch' statement is a duplicate of the default branch -inspection.duplicate.branches.in.switch.expression.default.message=Branch in 'switch' expression is a duplicate of the default branch -inspection.duplicate.branches.in.switch.default.result.message=Result expression in 'switch' expression is a duplicate of the default result -inspection.duplicate.branches.in.switch.fix.family.name=Merge duplicate branches of 'switch' statement -inspection.duplicate.branches.in.switch.expression.fix.family.name=Merge duplicate results of 'switch' expression -inspection.duplicate.branches.in.switch.fix.name=Merge with ''{0}'' -inspection.duplicate.branches.in.switch.redundant.fix.family.name=Delete redundant branches of 'switch' statement -inspection.duplicate.branches.in.switch.redundant.expression.fix.family.name=Delete redundant branches of 'switch' expression -inspection.duplicate.branches.in.switch.redundant.fix.name=Delete redundant 'switch' branch -inspection.duplicate.branches.in.switch.redundant.expression.fix.name=Delete redundant 'switch' result expression +inspection.duplicate.branches.in.switch.display.name=Duplicate branches in 'switch' +inspection.duplicate.branches.in.switch.message=Duplicate branch in 'switch' +inspection.duplicate.branches.in.switch.default.message=Branch in 'switch' is a duplicate of the default branch +inspection.duplicate.branches.in.switch.merge.fix.family.name=Merge duplicate branches in 'switch' +inspection.duplicate.branches.in.switch.merge.fix.name=Merge with ''{0}'' +inspection.duplicate.branches.in.switch.delete.fix.family.name=Delete redundant 'switch' branches +inspection.duplicate.branches.in.switch.delete.fix.name=Delete redundant 'switch' branch inspection.duplicate.branches.in.switch.merge.with.default.fix.name=Merge with the default 'switch' branch inspection.switch.labeled.rule.can.be.code.block.display.name=Labeled switch rule can have code block From 1a98569af920de7a77a176cf7cd5aba80765e3a2 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 4 Feb 2019 15:11:41 +0300 Subject: [PATCH 051/138] extract separate "Go To Declaration" action which knows nothing about "Show Usages" (IDEA-206322) --- .../actions/GotoDeclarationAction.java | 2 +- .../actions/GotoDeclarationOnlyAction.kt | 12 +++ .../actions/GotoDeclarationOnlyHandler.kt | 93 +++++++++++++++++++ .../src/messages/ActionsBundle.properties | 6 +- .../src/idea/LangActions.xml | 2 + 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index e34d7f847bc2..9768030bad63 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -178,7 +178,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return false; } - private static void gotoTargetElement(@NotNull PsiElement element, @NotNull Editor currentEditor, @NotNull PsiFile currentFile) { + static void gotoTargetElement(@NotNull PsiElement element, @NotNull Editor currentEditor, @NotNull PsiFile currentFile) { if (navigateInCurrentEditor(element, currentFile, currentEditor)) return; Navigatable navigatable = element instanceof Navigatable ? (Navigatable)element : EditSourceUtil.getDescriptor(element); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt new file mode 100644 index 000000000000..393d3f64e82e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyAction.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2019 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.navigation.actions + +import com.intellij.codeInsight.CodeInsightActionHandler + +/** + * Go To Declaration which doesn't invoke Show Usages if there are no declarations to go + */ +class GotoDeclarationOnlyAction : GotoDeclarationAction() { + + override fun getHandler(): CodeInsightActionHandler = GotoDeclarationOnlyHandler +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt new file mode 100644 index 000000000000..5e9bbc2747b7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt @@ -0,0 +1,93 @@ +// Copyright 2000-2019 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.navigation.actions + +import com.intellij.codeInsight.CodeInsightActionHandler +import com.intellij.codeInsight.CodeInsightBundle +import com.intellij.codeInsight.TargetElementUtil +import com.intellij.codeInsight.hint.HintManager +import com.intellij.codeInsight.navigation.NavigationUtil +import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.* +import com.intellij.featureStatistics.FeatureUsageTracker +import com.intellij.ide.util.DefaultPsiElementCellRenderer +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.IndexNotReadyException +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.search.PsiElementProcessor +import com.intellij.util.toArray + +object GotoDeclarationOnlyHandler : CodeInsightActionHandler { + + override fun startInWriteAction(): Boolean = false + + override fun invoke(project: Project, editor: Editor, file: PsiFile) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration.only") + + val dumbService = DumbService.getInstance(project) + try { + dumbService.isAlternativeResolveEnabled = true + val offset = editor.caretModel.offset + val elements = underModalProgress(project, "Resolving Reference...") { + findAllTargetElements(project, editor, offset) + } + + if (elements.size == 1) { + // simplest case + val element = elements[0] + val navElement = TargetElementUtil.getInstance().getGotoDeclarationTarget(element, element.navigationElement) + if (navElement != null) { + gotoTargetElement(navElement, editor, file) + } + } + else if (elements.isEmpty()) { + // this means either there is really nowhere to go or weird TargetElementUtil didn't return anything + val reference = TargetElementUtil.findReference(editor, offset) + if (reference != null) { + val targets = underModalProgress(project, "Resolving Reference...") { + TargetElementUtil.getInstance().getTargetCandidates(reference) + } + if (targets.isNotEmpty()) { + chooseAmbiguousTarget(editor, file, targets.toArray(PsiElement.EMPTY_ARRAY)) + return + } + } + //disable 'no declaration found' notification for keywords + if (!isKeywordUnderCaret(project, file, offset)) { + HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to") + } + } + else { + chooseAmbiguousTarget(editor, file, elements) + } + } + catch (e: IndexNotReadyException) { + dumbService.showDumbModeNotification("Navigation is not available here during index update") + } + finally { + dumbService.isAlternativeResolveEnabled = false + } + } + + private fun chooseAmbiguousTarget(editor: Editor, file: PsiFile, elements: Array) { + if (!editor.component.isShowing) return + chooseAmbiguousTarget(editor, CodeInsightBundle.message("declaration.navigation.title"), elements) { element -> + gotoTargetElement(element, editor, file) + } + } + + private fun chooseAmbiguousTarget(editor: Editor, title: String, elements: Array, processor: (PsiElement) -> Unit) { + require(elements.isNotEmpty()) + if (elements.size == 1) { + val element = elements[0] + processor(element) + return + } + val psiElementProcessor = PsiElementProcessor { + processor(it) + true + } + NavigationUtil.getPsiElementPopup(elements, DefaultPsiElementCellRenderer(), title, psiElementProcessor).showInBestPositionFor(editor) + } +} diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 7f61a7d8eeb4..010f987717f2 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -519,8 +519,10 @@ action.GotoAction.text=_Find Action... action.GotoAction.description=Quickly navigate to action by name action.GotoLine.text=_Line/Column... action.GotoLine.description=Navigate to a line (and/or column) in editor by its number -action.GotoDeclaration.text=_Declaration -action.GotoDeclaration.description=Navigate to the declaration of the symbol at caret +action.GotoDeclaration.text=Declaration or Usages +action.GotoDeclaration.description=Navigate to the declaration of the symbol at caret or show its usages +action.GotoDeclarationOnly.text=_Declaration +action.GotoDeclarationOnly.description=Navigate to the declaration of the symbol at caret action.GotoImplementation.text=I_mplementation(s) action.GotoImplementation.description=Navigate to the implementation(s) of the selected class or method action.GotoNextElementUnderCaretUsage.text=Go to next highlighted element usage diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index db293581cac2..99be30f44d98 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -139,6 +139,7 @@ + @@ -625,6 +626,7 @@ + From 1f7f3d9fdc2bf849be9a73cd8be4d6a83641ca7a Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 4 Feb 2019 15:43:35 +0300 Subject: [PATCH 052/138] make "Go To Declaration Or Usage" action choose between "Go To Declaration" or "Show Usages" (IDEA-206322) --- .../actions/GotoDeclarationAction.java | 92 +------------------ .../actions/GotoDeclarationActionHandler.java | 70 ++++++++++++++ 2 files changed, 75 insertions(+), 87 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index 9768030bad63..153029b56822 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -3,21 +3,18 @@ package com.intellij.codeInsight.navigation.actions; import com.google.common.annotations.VisibleForTesting; import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.actions.BaseCodeInsightAction; -import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.diagnostic.PluginException; -import com.intellij.featureStatistics.FeatureUsageTracker; -import com.intellij.find.actions.ShowUsagesAction; import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.ide.util.EditSourceUtil; import com.intellij.injected.editor.EditorWindow; import com.intellij.lang.LanguageNamesValidation; import com.intellij.lang.refactoring.NamesValidator; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; @@ -30,9 +27,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; import com.intellij.pom.Navigatable; @@ -56,13 +51,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -public class GotoDeclarationAction extends BaseCodeInsightAction implements CodeInsightActionHandler, DumbAware { +public class GotoDeclarationAction extends BaseCodeInsightAction implements DumbAware { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.navigation.actions.GotoDeclarationAction"); @NotNull @Override protected CodeInsightActionHandler getHandler() { - return this; + return new GotoDeclarationActionHandler(); } @Override @@ -70,65 +65,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return true; } - @Override - public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { - - DumbService.getInstance(project).setAlternativeResolveEnabled(true); - try { - int offset = editor.getCaretModel().getOffset(); - PsiElement[] elements = underModalProgress(project, "Resolving Reference...", () -> findAllTargetElements(project, editor, offset)); - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration"); - - if (elements.length != 1) { - if (elements.length == 0 && suggestCandidates(TargetElementUtil.findReference(editor, offset)).isEmpty()) { - PsiElement element = findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset()); - if (startFindUsages(editor, project, element)) { - return; - } - - //disable 'no declaration found' notification for keywords - if (isKeywordUnderCaret(project, file, offset)) return; - } - chooseAmbiguousTarget(editor, offset, elements, file); - return; - } - - PsiElement element = elements[0]; - if (element == findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset()) && - startFindUsages(editor, project, element)) { - return; - } - - PsiElement navElement = element.getNavigationElement(); - navElement = TargetElementUtil.getInstance().getGotoDeclarationTarget(element, navElement); - if (navElement != null) { - gotoTargetElement(navElement, editor, file); - } - } - catch (IndexNotReadyException e) { - DumbService.getInstance(project).showDumbModeNotification("Navigation is not available here during index update"); - } - finally { - DumbService.getInstance(project).setAlternativeResolveEnabled(false); - } - } - - private static boolean startFindUsages(@NotNull Editor editor, @NotNull Project project, PsiElement element) { - if (element == null) { - return false; - } - if (DumbService.getInstance(project).isDumb()) { - AnAction action = ActionManager.getInstance().getAction(ShowUsagesAction.ID); - String name = action.getTemplatePresentation().getText(); - DumbService.getInstance(project).showDumbModeNotification(ActionUtil.getUnavailableMessage(name, false)); - } - else { - RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor); - new ShowUsagesAction().startFindUsages(element, popupPosition, editor, ShowUsagesAction.getUsagesPageSize()); - } - return true; - } - static T underModalProgress(@NotNull Project project, @NotNull @Nls(capitalization = Nls.Capitalization.Title) String progressTitle, @NotNull Computable computable) throws ProcessCanceledException { @@ -147,19 +83,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return TargetElementUtil.getInstance().findTargetElement(editor, TargetElementUtil.ELEMENT_NAME_ACCEPTED, offset); } - private static void chooseAmbiguousTarget(final Editor editor, int offset, PsiElement[] elements, PsiFile currentFile) { - if (!editor.getComponent().isShowing()) return; - PsiElementProcessor navigateProcessor = element -> { - gotoTargetElement(element, editor, currentFile); - return true; - }; - boolean found = - chooseAmbiguousTarget(editor, offset, navigateProcessor, CodeInsightBundle.message("declaration.navigation.title"), elements); - if (!found) { - HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to"); - } - } - private static boolean navigateInCurrentEditor(@NotNull PsiElement element, @NotNull PsiFile currentFile, @NotNull Editor currentEditor) { if (element.getContainingFile() == currentFile && !currentEditor.isDisposed()) { int offset = element.getTextOffset(); @@ -240,11 +163,6 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code return TargetElementUtil.getInstance().getTargetCandidates(reference); } - @Override - public boolean startInWriteAction() { - return false; - } - @Nullable @TestOnly public static PsiElement findTargetElement(Project project, Editor editor, int offset) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java new file mode 100644 index 000000000000..64515e2f6153 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java @@ -0,0 +1,70 @@ +// Copyright 2000-2019 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.navigation.actions; + +import com.intellij.codeInsight.CodeInsightActionHandler; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.find.actions.ShowUsagesAction; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.IndexNotReadyException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.ui.awt.RelativePoint; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.findElementToShowUsagesOf; + +public final class GotoDeclarationActionHandler implements CodeInsightActionHandler { + + public static final GotoDeclarationActionHandler INSTANCE = new GotoDeclarationActionHandler(); + + @Override + public boolean startInWriteAction() { + return false; + } + + @Override + public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration"); + final PsiElement declarationElement = findDeclarationElement(project, editor); + if (declarationElement == null) { + GotoDeclarationOnlyHandler.INSTANCE.invoke(project, editor, file); + } + else { + startFindUsages(editor, project, declarationElement); + } + } + + @Nullable + private static PsiElement findDeclarationElement(@NotNull Project project, @NotNull Editor editor) { + final DumbService dumbService = DumbService.getInstance(project); + try { + return dumbService.computeWithAlternativeResolveEnabled(() -> { + int offset = editor.getCaretModel().getOffset(); + return findElementToShowUsagesOf(editor, offset); + }); + } + catch (IndexNotReadyException e) { + dumbService.showDumbModeNotification("Navigation is not available here during index update"); + return null; + } + } + + private static void startFindUsages(@NotNull Editor editor, @NotNull Project project, @NotNull PsiElement element) { + if (DumbService.getInstance(project).isDumb()) { + AnAction action = ActionManager.getInstance().getAction(ShowUsagesAction.ID); + String name = action.getTemplatePresentation().getText(); + DumbService.getInstance(project).showDumbModeNotification(ActionUtil.getUnavailableMessage(name, false)); + } + else { + RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor); + new ShowUsagesAction().startFindUsages(element, popupPosition, editor, ShowUsagesAction.getUsagesPageSize()); + } + } +} From c33423601a2f73ecf3cb5dce47cb69da559c6592 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 4 Feb 2019 17:16:21 +0300 Subject: [PATCH 053/138] use static instance of GotoDeclarationActionHandler in GotoDeclarationAction (IDEA-206322) --- .../codeInsight/navigation/actions/GotoDeclarationAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index 153029b56822..091afb99ecda 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -57,7 +57,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Dumb @NotNull @Override protected CodeInsightActionHandler getHandler() { - return new GotoDeclarationActionHandler(); + return GotoDeclarationActionHandler.INSTANCE; } @Override From 1ace9ab2c3c8f5dde09e3257d2facfdf867a6703 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 15:09:56 +0100 Subject: [PATCH 054/138] lambda -> method ref: reuse comment tracker (IDEA-189934) --- .../quickFix/lambda2methodReference/afterComments.java | 2 ++ .../quickFix/lambda2methodReference/beforeComments.java | 5 ++++- .../afterFilterFlatMapCollectionFilterMapCollect.java | 3 ++- .../streamApiCallChains/afterEntrySetAdvanced.java | 3 ++- .../LambdaCanBeMethodReferenceInspection.java | 8 ++------ 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java index a134d04c80f2..d75fc244ce24 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/afterComments.java @@ -5,6 +5,8 @@ class Example { { //my comments here + //1 + //2 Runnable r = this::m } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java index e6373b741e74..879e93f83e2c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambda2methodReference/beforeComments.java @@ -6,7 +6,10 @@ class Example { { Runnable r = () -> { //my comments here - m(); + m() + //1 + //2 + ; } } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java index 354a6127d8e6..9aba26d77cfd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/filter/afterFilterFlatMapCollectionFilterMapCollect.java @@ -4,7 +4,8 @@ import java.util.stream.Collectors; public class Main { public void test(List> nested) { - /*non-equal*//*empty*/ + /*non-equal*/ + /*empty*/ List result = nested.stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> str./*startswith*/startsWith("xyz")).map(String::trim).collect(Collectors.toList()); // 1 /*target is here*/ diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java b/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java index 69f3fb0f63b1..ae5bbbabbbeb 100644 --- a/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterEntrySetAdvanced.java @@ -34,7 +34,8 @@ class Scratch { } void testDecl(Map map) { - /*5*//*6*/ + /*5*/ + /*6*/ String res = map.values(/*0*/).stream().filter(val1 -> { /*1*/ return !val1./*2*/isEmpty(); diff --git a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java index 5774daa3828e..d929ca8b4333 100644 --- a/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java +++ b/plugins/InspectionGadgets/src/com/intellij/codeInspection/LambdaCanBeMethodReferenceInspection.java @@ -18,7 +18,7 @@ import com.intellij.psi.util.*; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.ContainerUtil; +import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -628,16 +628,13 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI final PsiType denotableFunctionalInterfaceType = RefactoringChangeUtil.getTypeByExpression(lambda); if (denotableFunctionalInterfaceType == null) return lambda; - Collection comments = ContainerUtil.map(PsiTreeUtil.findChildrenOfType(lambda, PsiComment.class), - (comment) -> (PsiComment)comment.copy()); - final String methodRefText = createMethodReferenceText(body, functionalInterfaceType, lambda.getParameterList().getParameters()); if (methodRefText != null) { final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); final PsiExpression psiExpression = factory.createExpressionFromText(methodRefText, lambda); final SmartTypePointer typePointer = SmartTypePointerManager.getInstance(project).createSmartTypePointer(denotableFunctionalInterfaceType); - PsiExpression replace = (PsiExpression)lambda.replace(psiExpression); + PsiExpression replace = (PsiExpression)new CommentTracker().replaceAndRestoreComments(lambda, psiExpression); final PsiType functionalTypeAfterReplacement = GenericsUtil.getVariableTypeByExpressionType(((PsiMethodReferenceExpression)replace).getFunctionalInterfaceType()); functionalInterfaceType = typePointer.getType(); if (functionalInterfaceType != null && (functionalTypeAfterReplacement == null || @@ -652,7 +649,6 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI replace = (PsiExpression)replace.replace(cast); } - AnonymousCanBeLambdaInspection.restoreComments(comments, replace); JavaCodeStyleManager.getInstance(project).shortenClassReferences(replace); return replace; } From 092e5f964360eb36a2239c0da5092e805637a62d Mon Sep 17 00:00:00 2001 From: "sergey.vasiliev" Date: Mon, 4 Feb 2019 14:34:02 +0100 Subject: [PATCH 055/138] remove a statistics custom service from startup activities --- java/java-impl/src/META-INF/libraryJarUsage.xml | 1 - .../libraryJar/LibraryJarStatisticsService.java | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/java/java-impl/src/META-INF/libraryJarUsage.xml b/java/java-impl/src/META-INF/libraryJarUsage.xml index 0192efe1b571..0c99b9031cd0 100644 --- a/java/java-impl/src/META-INF/libraryJarUsage.xml +++ b/java/java-impl/src/META-INF/libraryJarUsage.xml @@ -1,7 +1,6 @@ - diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java index 56603aac3b7b..75ddc4ce8905 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/LibraryJarStatisticsService.java @@ -35,7 +35,7 @@ import java.net.URL; /** * @author Ivan Chirkov */ -public class LibraryJarStatisticsService implements StartupActivity, DumbAware { +public class LibraryJarStatisticsService implements DumbAware { private static final String FILE_NAME = "statistics/library-jar-statistics.xml"; @@ -90,11 +90,4 @@ public class LibraryJarStatisticsService implements StartupActivity, DumbAware { return null; } - - @Override - public void runActivity(@NotNull Project project) { - final Application application = ApplicationManager.getApplication(); - if (application.isUnitTestMode() || application.isHeadlessEnvironment()) return; - ApplicationManager.getApplication().executeOnPooledThread((Runnable)() -> getInstance().getTechnologyDescriptors()); - } } From d825ff4933b0065a6b4e50864bf1c0e3171c6e29 Mon Sep 17 00:00:00 2001 From: "sergey.vasiliev" Date: Mon, 4 Feb 2019 14:48:22 +0100 Subject: [PATCH 056/138] FUS-241 add contexts to `javaLibraries` statistics group --- .../libraryJar/FUSLibraryJarUsagesCollector.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java index a60cbab7d26c..6f548b69b908 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java @@ -2,6 +2,7 @@ package com.intellij.internal.statistic.libraryJar; import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.ProjectUsagesCollector; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; @@ -45,11 +46,9 @@ public class FUSLibraryJarUsagesCollector extends ProjectUsagesCollector { VirtualFile jarFile = JarFileSystem.getInstance().getVirtualFileForJar(psiClass.getContainingFile().getVirtualFile()); if (jarFile != null) { String version = getVersionByJarManifest(jarFile); - if (version == null) { - version = getVersionByJarFileName(jarFile.getName()); - } - if (version != null && StringUtil.containsChar(version, '.')) { - result.add(new UsageDescriptor(descriptor.myName + "_" + version, 1)); + if (version == null) version = getVersionByJarFileName(jarFile.getName()); + if (StringUtil.isNotEmpty(version)) { + result.add(new UsageDescriptor(descriptor.myName, 1, new FeatureUsageData().addOS().addVersionByString(version))); } } } From 678053211246d154f43dc9af4b5bc72f6b5126a2 Mon Sep 17 00:00:00 2001 From: "sergey.vasiliev" Date: Mon, 4 Feb 2019 15:07:19 +0100 Subject: [PATCH 057/138] FUS-241 add contexts to `javaLibraries`('javaLibraryJars') statistics group --- .../statistic/libraryJar/FUSLibraryJarUsagesCollector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java index 6f548b69b908..9997555154a1 100644 --- a/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java +++ b/java/java-impl/src/com/intellij/internal/statistic/libraryJar/FUSLibraryJarUsagesCollector.java @@ -74,6 +74,6 @@ public class FUSLibraryJarUsagesCollector extends ProjectUsagesCollector { @NotNull @Override public String getGroupId() { - return "javaLibraries"; + return "javaLibraryJars"; } } \ No newline at end of file From be90c2b8d78d21a8b985efa1fef1429e93915961 Mon Sep 17 00:00:00 2001 From: "Dmitry.Krasilschikov" Date: Mon, 4 Feb 2019 14:24:35 +0200 Subject: [PATCH 058/138] IDEA-200666 IDEA-206344 don't persist editors' color scheme --- .../intellij/ide/actions/RecentLocationManager.java | 6 ------ .../intellij/ide/actions/RecentLocationsAction.java | 12 +----------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java index d38becfbb51e..93ff22ede233 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationManager.java @@ -92,12 +92,6 @@ public class RecentLocationManager implements ProjectComponent { return item == null ? null : item.getPositionOffsetMarker(); } - @Nullable - EditorColorsScheme getColorScheme(@NotNull PlaceInfo placeInfo, boolean showChanged) { - PlaceInfoPersistentItem item = getMap(showChanged).get(placeInfo); - return item == null ? null : item.getScheme(); - } - private void subscribeOnExternalChange(@NotNull MessageBusConnection connection) { connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @Override diff --git a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java index 26c0337c688d..cf07ac1f46b8 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/RecentLocationsAction.java @@ -550,22 +550,12 @@ public class RecentLocationsAction extends AnAction { @NotNull Document document, @NotNull PlaceInfo placeInfo, @NotNull TextRange textRange) { - EditorColorsScheme colorsScheme = setupColorScheme(project, editor, placeInfo); + EditorColorsScheme colorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); applySyntaxHighlighting(project, editor, document, colorsScheme, textRange, placeInfo); applyHighlightingPasses(project, editor, document, colorsScheme, textRange); } - @NotNull - private static EditorColorsScheme setupColorScheme(@NotNull Project project, @NotNull EditorEx editor, @NotNull PlaceInfo placeInfo) { - EditorColorsScheme colorsScheme = RecentLocationManager.getInstance(project).getColorScheme(placeInfo, showChanged(project)); - if (colorsScheme == null) { - colorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); - } - editor.setColorsScheme(colorsScheme); - return colorsScheme; - } - private static void applySyntaxHighlighting(@NotNull Project project, @NotNull EditorEx editor, @NotNull Document document, From 73602e0415adec09b8e016d0650b952995ee62f2 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 14:35:52 +0300 Subject: [PATCH 059/138] diff: extract mutable diff request support --- .../diff/actions/ShowBlankDiffWindowAction.kt | 111 ++++++------------ .../actions/impl/MutableDiffRequestChain.kt | 72 ++++++++++++ 2 files changed, 110 insertions(+), 73 deletions(-) create mode 100644 platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt diff --git a/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt b/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt index 7cc2a3462347..4ce5c5d15545 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt +++ b/platform/diff-impl/src/com/intellij/diff/actions/ShowBlankDiffWindowAction.kt @@ -2,12 +2,10 @@ package com.intellij.diff.actions import com.intellij.diff.* -import com.intellij.diff.chains.DiffRequestChainBase -import com.intellij.diff.chains.DiffRequestProducer +import com.intellij.diff.actions.impl.MutableDiffRequestChain import com.intellij.diff.contents.DocumentContent import com.intellij.diff.contents.FileContent import com.intellij.diff.requests.DiffRequest -import com.intellij.diff.requests.SimpleDiffRequest import com.intellij.diff.tools.simple.SimpleDiffTool import com.intellij.diff.tools.util.DiffDataKeys import com.intellij.diff.tools.util.side.TwosideTextDiffViewer @@ -21,10 +19,9 @@ import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptor import com.intellij.openapi.fileEditor.impl.EditorWindow -import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project -import com.intellij.openapi.util.UserDataHolder +import com.intellij.openapi.util.Key import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile @@ -32,6 +29,8 @@ import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.Transferable import java.io.File +private val BLANK_KEY = Key.create("Diff.BlankWindow") + class ShowBlankDiffWindowAction : DumbAwareAction() { init { isEnabledInModalContext = true @@ -49,51 +48,56 @@ class ShowBlankDiffWindowAction : DumbAwareAction() { val content1 = createEditableContent(project, StringUtil.notNullize(defaultText)) val content2 = createEditableContent(project, "") - val chain = BlankWindowDiffRequestChain(content1, content2) + val chain = MutableDiffRequestChain(content1, content2) chain.putUserData(DiffUserDataKeysEx.FORCE_DIFF_TOOL, SimpleDiffTool.INSTANCE) + chain.putUserData(BLANK_KEY, true) DiffManager.getInstance().showDiff(project, chain, DiffDialogHints.DEFAULT) } } internal class SwitchToBlankEditorAction : BlankActionBase() { - override fun isEnabled(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side): Boolean { - val content = side.select(chain.content1, chain.content2) + override fun isEnabled(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side): Boolean { + val content = side.select(helper.chain.content1, helper.chain.content2) return content is FileContent } - override fun perform(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side) { + override fun perform(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side) { val newContent = createEditableContent(viewer.project, "") - chain.setContent(newContent, side) + helper.setContent(newContent, side) - context.reloadDiffRequest() + helper.fireRequestUpdated() } } internal class SwitchToFileEditorAction : BlankActionBase() { - override fun isEnabled(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side): Boolean { + override fun isEnabled(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side): Boolean { return true } - override fun perform(viewer: TwosideTextDiffViewer, chain: BlankWindowDiffRequestChain, context: DiffContextEx, side: Side) { + override fun perform(viewer: TwosideTextDiffViewer, helper: MutableDiffRequestChain.Helper, side: Side) { val descriptor = FileChooserDescriptor(true, false, false, false, false, false) descriptor.title = "Select File to Compare" descriptor.description = "" val file = FileChooser.chooseFile(descriptor, viewer.component, viewer.project, null) ?: return val newContent = createFileContent(viewer.project, file) ?: return - chain.setContent(newContent, side) + helper.setContent(newContent, side) - context.reloadDiffRequest() + helper.fireRequestUpdated() } } internal abstract class BlankActionBase : DumbAwareAction() { override fun update(e: AnActionEvent) { val viewer = e.getData(DiffDataKeys.DIFF_VIEWER) as? TwosideTextDiffViewer - val request = e.getData(DiffDataKeys.DIFF_REQUEST) as? BlankWindowDiffRequest - val context = e.getData(DiffDataKeys.DIFF_CONTEXT) as? DiffContextEx - if (viewer == null || request == null || context == null) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext) + if (viewer == null || helper == null) { + e.presentation.isEnabledAndVisible = false + return + } + + if (helper.chain.getUserData(BLANK_KEY) != true) { e.presentation.isEnabledAndVisible = false return } @@ -105,45 +109,42 @@ internal abstract class BlankActionBase : DumbAwareAction() { return } - e.presentation.isEnabledAndVisible = isEnabled(viewer, request.chain, context, side) + e.presentation.isEnabledAndVisible = isEnabled(viewer, helper, side) } override fun actionPerformed(e: AnActionEvent) { val viewer = e.getData(DiffDataKeys.DIFF_VIEWER) as TwosideTextDiffViewer - val request = e.getData(DiffDataKeys.DIFF_REQUEST) as BlankWindowDiffRequest - val context = e.getData(DiffDataKeys.DIFF_CONTEXT) as DiffContextEx + val helper = MutableDiffRequestChain.createHelper(e.dataContext)!! val editor = e.getData(CommonDataKeys.EDITOR) val side = Side.fromValue(viewer.editors, editor)!! - perform(viewer, request.chain, context, side) + perform(viewer, helper, side) } protected abstract fun isEnabled(viewer: TwosideTextDiffViewer, - chain: BlankWindowDiffRequestChain, - context: DiffContextEx, + helper: MutableDiffRequestChain.Helper, side: Side): Boolean protected abstract fun perform(viewer: TwosideTextDiffViewer, - chain: BlankWindowDiffRequestChain, - context: DiffContextEx, + helper: MutableDiffRequestChain.Helper, side: Side) } class ShowBlankDiffWindowDiffExtension : DiffExtension() { override fun onViewerCreated(viewer: FrameDiffTool.DiffViewer, context: DiffContext, request: DiffRequest) { - if (request is BlankWindowDiffRequest && - context is DiffContextEx && - viewer is TwosideTextDiffViewer) { - DnDHandler(viewer, context, request.chain, Side.LEFT).install() - DnDHandler(viewer, context, request.chain, Side.RIGHT).install() + if (viewer is TwosideTextDiffViewer) { + val helper = MutableDiffRequestChain.createHelper(context, request) ?: return + if (helper.chain.getUserData(BLANK_KEY) == true) { + DnDHandler(viewer, helper, Side.LEFT).install() + DnDHandler(viewer, helper, Side.RIGHT).install() + } } } } private class DnDHandler(val viewer: TwosideTextDiffViewer, - val context: DiffContextEx, - val chain: BlankWindowDiffRequestChain, + val helper: MutableDiffRequestChain.Helper, val side: Side) : EditorDropHandler { fun install() { val editor = viewer.getEditor(side) as? EditorImpl ?: return @@ -156,7 +157,7 @@ private class DnDHandler(val viewer: TwosideTextDiffViewer, override fun handleDrop(t: Transferable, project: Project?, editorWindow: EditorWindow?) { val success = doHandleDnD(t) - if (success) context.reloadDiffRequest() + if (success) helper.fireRequestUpdated() } private fun doHandleDnD(transferable: Transferable): Boolean { @@ -164,14 +165,14 @@ private class DnDHandler(val viewer: TwosideTextDiffViewer, if (files != null) { if (files.size == 1) { val newContent = createFileContent(viewer.project, files[0]) ?: return false - chain.setContent(newContent, side) + helper.setContent(newContent, side) return true } if (files.size >= 2) { val newContent1 = createFileContent(viewer.project, files[0]) ?: return false val newContent2 = createFileContent(viewer.project, files[1]) ?: return false - chain.setContent(newContent1, Side.LEFT) - chain.setContent(newContent2, Side.RIGHT) + helper.setContent(newContent1, Side.LEFT) + helper.setContent(newContent2, Side.RIGHT) return true } } @@ -191,39 +192,3 @@ private fun createFileContent(project: Project?, file: File): DocumentContent? { private fun createFileContent(project: Project?, file: VirtualFile): DocumentContent? { return DiffContentFactory.getInstance().createDocument(project, file) } - -internal class BlankWindowDiffRequestChain(var content1: DocumentContent, var content2: DocumentContent) : DiffRequestChainBase() { - var title1: String? = getTitleFor(content1) - var title2: String? = getTitleFor(content2) - - override fun getRequests(): List { - return listOf(object : DiffRequestProducer { - override fun getName(): String { - return "Change" - } - - override fun process(context: UserDataHolder, indicator: ProgressIndicator): DiffRequest { - return BlankWindowDiffRequest(this@BlankWindowDiffRequestChain) - } - }) - } - - fun setContent(newContent: DocumentContent, side: Side) { - val title = getTitleFor(newContent) - - if (side.isLeft) { - content1 = newContent - title1 = title - } - else { - content2 = newContent - title2 = title - } - } - - private fun getTitleFor(content: DocumentContent) = - if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null -} - -private class BlankWindowDiffRequest internal constructor(val chain: BlankWindowDiffRequestChain) - : SimpleDiffRequest(null, chain.content1, chain.content2, chain.title1, chain.title2) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt new file mode 100644 index 000000000000..7c5132625a27 --- /dev/null +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt @@ -0,0 +1,72 @@ +// Copyright 2000-2019 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.diff.actions.impl + +import com.intellij.diff.DiffContext +import com.intellij.diff.DiffContextEx +import com.intellij.diff.DiffRequestFactory +import com.intellij.diff.chains.DiffRequestChainBase +import com.intellij.diff.chains.DiffRequestProducer +import com.intellij.diff.contents.DiffContent +import com.intellij.diff.contents.FileContent +import com.intellij.diff.requests.DiffRequest +import com.intellij.diff.requests.SimpleDiffRequest +import com.intellij.diff.tools.util.DiffDataKeys +import com.intellij.diff.util.Side +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.util.UserDataHolder + +class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffContent) : DiffRequestChainBase() { + var title1: String? = getTitleFor(content1) + var title2: String? = getTitleFor(content2) + + override fun getRequests(): List { + return listOf(object : DiffRequestProducer { + override fun getName(): String { + return "Change" + } + + override fun process(context: UserDataHolder, indicator: ProgressIndicator): DiffRequest { + return MutableChainDiffRequest(this@MutableDiffRequestChain) + } + }) + } + + companion object { + fun createHelper(context: DiffContext, request: DiffRequest): Helper? { + if (context !is DiffContextEx || request !is MutableChainDiffRequest) return null + return Helper(request.chain, context) + } + + fun createHelper(dataContext: DataContext): Helper? { + val context = dataContext.getData(DiffDataKeys.DIFF_CONTEXT) as? DiffContextEx ?: return null + val request = dataContext.getData(DiffDataKeys.DIFF_REQUEST) as? MutableChainDiffRequest ?: return null + return Helper(request.chain, context) + } + } + + data class Helper(val chain: MutableDiffRequestChain, val context: DiffContextEx) { + fun setContent(newContent: DiffContent, side: Side) { + val title = getTitleFor(newContent) + + if (side.isLeft) { + chain.content1 = newContent + chain.title1 = title + } + else { + chain.content2 = newContent + chain.title2 = title + } + } + + fun fireRequestUpdated() { + context.reloadDiffRequest() + } + } +} + +private fun getTitleFor(content: DiffContent) = + if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null + +private class MutableChainDiffRequest(val chain: MutableDiffRequestChain) + : SimpleDiffRequest(null, chain.content1, chain.content2, chain.title1, chain.title2) From 2a8f1089544e67809d9447ab049a29791e181262 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 14:39:10 +0300 Subject: [PATCH 060/138] IDEA-48213 diff: allow to swap sides in "Blank Diff Window" --- .../actions/impl/MutableDiffRequestChain.kt | 31 ++++++++++++++++++- .../src/idea/PlatformActions.xml | 4 +++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt index 7c5132625a27..f8fdc63053ff 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt @@ -12,8 +12,10 @@ import com.intellij.diff.requests.DiffRequest import com.intellij.diff.requests.SimpleDiffRequest import com.intellij.diff.tools.util.DiffDataKeys import com.intellij.diff.util.Side +import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.util.UserDataHolder class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffContent) : DiffRequestChainBase() { @@ -47,8 +49,10 @@ class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffConte data class Helper(val chain: MutableDiffRequestChain, val context: DiffContextEx) { fun setContent(newContent: DiffContent, side: Side) { - val title = getTitleFor(newContent) + setContent(newContent, getTitleFor(newContent), side) + } + fun setContent(newContent: DiffContent, title: String?, side: Side) { if (side.isLeft) { chain.content1 = newContent chain.title1 = title @@ -65,6 +69,31 @@ class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffConte } } +internal class SwapDiffSidesAction : DumbAwareAction() { + override fun update(e: AnActionEvent) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext) + if (helper == null) { + e.presentation.isEnabledAndVisible = false + return + } + + e.presentation.isEnabledAndVisible = true + } + + override fun actionPerformed(e: AnActionEvent) { + val helper = MutableDiffRequestChain.createHelper(e.dataContext)!! + + val oldContent1 = helper.chain.content1 + val oldContent2 = helper.chain.content2 + val oldTitle1 = helper.chain.title1 + val oldTitle2 = helper.chain.title2 + + helper.setContent(oldContent1, oldTitle1, Side.RIGHT) + helper.setContent(oldContent2, oldTitle2, Side.LEFT) + helper.fireRequestUpdated() + } +} + private fun getTitleFor(content: DiffContent) = if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 7e2ba7b31cff..bd6a8313ca76 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -912,6 +912,10 @@ + + + + From 5ddcd517db98c7a2eadad4c12b0335bbee895867 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 15:47:56 +0300 Subject: [PATCH 061/138] diff: allow to mark DiffContent as read-only --- .../intellij/diff/util/DiffUserDataKeys.java | 8 +++++++ .../CompareClipboardWithSelectionAction.java | 2 +- .../tools/util/base/TextDiffViewerUtil.java | 22 +++++++++++-------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java b/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java index c42b19b4aa66..ad2fd2e83794 100644 --- a/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java +++ b/platform/diff-api/src/com/intellij/diff/util/DiffUserDataKeys.java @@ -39,6 +39,9 @@ public interface DiffUserDataKeys { Key> SCROLL_TO_LINE_THREESIDE = Key.create("Diff.ScrollToLineThreeside"); Key HELP_ID = Key.create("Diff.HelpId"); + /** + * Used IN ADDITION to FORCE_READ_ONLY data key + */ Key FORCE_READ_ONLY_CONTENTS = Key.create("Diff.ForceReadOnlyContents"); // @@ -67,5 +70,10 @@ public interface DiffUserDataKeys { Key> CONTEXT_ACTIONS = Key.create("Diff.ContextActions"); Key DATA_PROVIDER = Key.create("Diff.DataProvider"); Key GO_TO_SOURCE_DISABLE = Key.create("Diff.GoToSourceDisable"); + + // + // DiffContext / DiffRequest / DiffContent + // + Key FORCE_READ_ONLY = Key.create("Diff.ForceReadOnly"); } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java index b82c1fd5efa3..b6cf3d975b6a 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java @@ -95,7 +95,7 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { SimpleDiffRequest request = new SimpleDiffRequest(title, content1, content2, title1, title2); request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, editor.getCaretModel().getLogicalPosition().line)); if (editor.isViewer()) { - request.putUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS, new boolean[]{false, true}); + content2.putUserData(DiffUserDataKeys.FORCE_READ_ONLY, true); } return request; } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java index 8b6ff9d2b7df..d7e141bbc698 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffViewerUtil.java @@ -24,7 +24,6 @@ import com.intellij.diff.tools.util.FoldingModelSupport; import com.intellij.diff.tools.util.base.TextDiffSettingsHolder.TextDiffSettings; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.DiffUserDataKeysEx; -import com.intellij.diff.util.DiffUtil; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -50,6 +49,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static com.intellij.diff.util.DiffUtil.isUserDataFlagSet; import static com.intellij.util.containers.ContainerUtil.list; public class TextDiffViewerUtil { @@ -78,7 +78,7 @@ public class TextDiffViewerUtil { if (settings == null) { settings = TextDiffSettings.getSettings(context.getUserData(DiffUserDataKeys.PLACE)); context.putUserData(TextDiffSettings.KEY, settings); - if (DiffUtil.isUserDataFlagSet(DiffUserDataKeys.DO_NOT_IGNORE_WHITESPACES, context)) { + if (isUserDataFlagSet(DiffUserDataKeys.DO_NOT_IGNORE_WHITESPACES, context)) { settings.setIgnorePolicy(IgnorePolicy.DEFAULT); } } @@ -87,17 +87,21 @@ public class TextDiffViewerUtil { @NotNull public static boolean[] checkForceReadOnly(@NotNull DiffContext context, @NotNull ContentDiffRequest request) { - int contentCount = request.getContents().size(); + List contents = request.getContents(); + int contentCount = contents.size(); boolean[] result = new boolean[contentCount]; - if (DiffUtil.isUserDataFlagSet(DiffUserDataKeys.FORCE_READ_ONLY, request, context)) { - Arrays.fill(result, true); - return result; + boolean[] data = request.getUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS); + if (data != null && data.length != contentCount) { + LOG.warn("Invalid FORCE_READ_ONLY_CONTENTS key value: " + request); + data = null; } - boolean[] data = request.getUserData(DiffUserDataKeys.FORCE_READ_ONLY_CONTENTS); - if (data != null && data.length == contentCount) { - return data; + for (int i = 0; i < contents.size(); i++) { + if (isUserDataFlagSet(DiffUserDataKeys.FORCE_READ_ONLY, contents.get(i), request, context) || + data != null && data[i]) { + result[i] = true; + } } return result; From 1d3d5ef44051234737d13803854566428e6fc491 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 16:40:49 +0300 Subject: [PATCH 062/138] IDEA-48213 diff: allow to swap sides in "Compare Files" --- .../diff/actions/BaseShowDiffAction.java | 39 +++++++++++++++---- .../CompareClipboardWithSelectionAction.java | 23 +++++------ .../actions/CompareFileWithEditorAction.java | 17 ++++---- .../diff/actions/CompareFilesAction.java | 9 +++-- .../actions/impl/MutableDiffRequestChain.kt | 17 +++++++- 5 files changed, 71 insertions(+), 34 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java index 515fdd7e3c00..66cd88b78bd6 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java @@ -15,20 +15,24 @@ */ package com.intellij.diff.actions; +import com.intellij.diff.DiffContentFactory; +import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffManager; -import com.intellij.diff.requests.DiffRequest; +import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; +import com.intellij.diff.contents.DiffContent; import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithoutContent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -abstract class BaseShowDiffAction extends AnAction implements DumbAware { +public abstract class BaseShowDiffAction extends DumbAwareAction { BaseShowDiffAction() { setEnabledInModalContext(true); } @@ -46,10 +50,10 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); - DiffRequest request = getDiffRequest(e); - if (request == null) return; + DiffRequestChain chain = getDiffRequestChain(e); + if (chain == null) return; - DiffManager.getInstance().showDiff(project, request); + DiffManager.getInstance().showDiff(project, chain, DiffDialogHints.DEFAULT); } protected abstract boolean isAvailable(@NotNull AnActionEvent e); @@ -59,5 +63,24 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { } @Nullable - protected abstract DiffRequest getDiffRequest(@NotNull AnActionEvent e); + protected abstract DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e); + + @NotNull + protected static MutableDiffRequestChain createMutableChainFromFiles(@Nullable Project project, + @NotNull VirtualFile file1, + @NotNull VirtualFile file2) { + DiffContentFactory contentFactory = DiffContentFactory.getInstance(); + DiffRequestFactory requestFactory = DiffRequestFactory.getInstance(); + + DiffContent content1 = contentFactory.create(project, file1); + DiffContent content2 = contentFactory.create(project, file2); + + MutableDiffRequestChain chain = new MutableDiffRequestChain(content1, content2); + + chain.setWindowTitle(requestFactory.getTitle(file1, file2)); + chain.setTitle1(requestFactory.getContentTitle(file1)); + chain.setTitle2(requestFactory.getContentTitle(file2)); + + return chain; + } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java index b6cf3d975b6a..42b9bb517829 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareClipboardWithSelectionAction.java @@ -17,11 +17,12 @@ package com.intellij.diff.actions; import com.intellij.diff.DiffContentFactory; import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; -import com.intellij.diff.requests.SimpleDiffRequest; import com.intellij.diff.tools.util.DiffDataKeys; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.Side; @@ -77,7 +78,7 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { @Nullable @Override - protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); Editor editor = getEditor(e); FileType editorFileType = getEditorFileType(e); @@ -87,17 +88,15 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { DocumentContent content2 = createContent(project, editor, editorFileType, selectedContent); DocumentContent content1 = DiffContentFactory.getInstance().createClipboardContent(project, content2); - String title1 = DiffBundle.message("diff.content.clipboard.content.title"); - String title2 = createContentTitle(editor); + MutableDiffRequestChain chain = new MutableDiffRequestChain(content1, content2); + chain.setWindowTitle(DiffBundle.message("diff.clipboard.vs.editor.dialog.title")); + chain.setTitle1(DiffBundle.message("diff.content.clipboard.content.title")); + chain.setTitle2(createContentTitle(editor)); - String title = DiffBundle.message("diff.clipboard.vs.editor.dialog.title"); + int currentLine = editor.getCaretModel().getLogicalPosition().line; + chain.putRequestUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, currentLine)); - SimpleDiffRequest request = new SimpleDiffRequest(title, content1, content2, title1, title2); - request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, editor.getCaretModel().getLogicalPosition().line)); - if (editor.isViewer()) { - content2.putUserData(DiffUserDataKeys.FORCE_READ_ONLY, true); - } - return request; + return chain; } @NotNull @@ -124,6 +123,8 @@ public class CompareClipboardWithSelectionAction extends BaseShowDiffAction { content = DiffContentFactory.getInstance().createFragment(project, content, range); } + if (editor.isViewer()) content.putUserData(DiffUserDataKeys.FORCE_READ_ONLY, true); + return content; } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java index 5b38968f09e7..a64f91b7c0c2 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java @@ -3,11 +3,10 @@ */ package com.intellij.diff.actions; -import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.actions.impl.MutableDiffRequestChain; +import com.intellij.diff.chains.DiffRequestChain; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.contents.DocumentContent; -import com.intellij.diff.requests.ContentDiffRequest; -import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.Side; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -70,24 +69,24 @@ public class CompareFileWithEditorAction extends BaseShowDiffAction { @Nullable @Override - protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); VirtualFile selectedFile = getSelectedFile(e); VirtualFile currentFile = getEditingFile(e); - assert selectedFile != null && currentFile != null; - ContentDiffRequest request = DiffRequestFactory.getInstance().createFromFiles(project, selectedFile, currentFile); + MutableDiffRequestChain chain = createMutableChainFromFiles(project, selectedFile, currentFile); - DiffContent editorContent = request.getContents().get(1); + DiffContent editorContent = chain.getContent2(); if (editorContent instanceof DocumentContent) { Editor[] editors = EditorFactory.getInstance().getEditors(((DocumentContent)editorContent).getDocument()); if (editors.length != 0) { - request.putUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, editors[0].getCaretModel().getLogicalPosition().line)); + int currentLine = editors[0].getCaretModel().getLogicalPosition().line; + chain.putRequestUserData(DiffUserDataKeys.SCROLL_TO_LINE, Pair.create(Side.RIGHT, currentLine)); } } - return request; + return chain; } } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index 1d1bc17ae61f..ddb6384ae1f1 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -15,7 +15,8 @@ */ package com.intellij.diff.actions; -import com.intellij.diff.DiffRequestFactory; +import com.intellij.diff.chains.DiffRequestChain; +import com.intellij.diff.chains.SimpleDiffRequestChain; import com.intellij.diff.requests.DiffRequest; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.highlighter.ArchiveFileType; @@ -96,11 +97,11 @@ public class CompareFilesAction extends BaseShowDiffAction { @Nullable @Override - protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); DiffRequest diffRequest = e.getData(DIFF_REQUEST); if (diffRequest != null) { - return diffRequest; + return new SimpleDiffRequestChain(diffRequest); } VirtualFile file1; @@ -124,7 +125,7 @@ public class CompareFilesAction extends BaseShowDiffAction { if (type1 == Type.DIRECTORY || type2 == Type.DIRECTORY) FeatureUsageTracker.getInstance().triggerFeatureUsed("dir.diff"); if (type1 == Type.ARCHIVE || type2 == Type.ARCHIVE) FeatureUsageTracker.getInstance().triggerFeatureUsed("jar.diff"); - return DiffRequestFactory.getInstance().createFromFiles(project, file1, file2); + return createMutableChainFromFiles(project, file1, file2); } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt index f8fdc63053ff..1c44e65bca66 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt +++ b/platform/diff-impl/src/com/intellij/diff/actions/impl/MutableDiffRequestChain.kt @@ -16,12 +16,19 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.util.Key import com.intellij.openapi.util.UserDataHolder class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffContent) : DiffRequestChainBase() { + private val requestUserData: MutableList, Any>> = mutableListOf() + var windowTitle: String? = null var title1: String? = getTitleFor(content1) var title2: String? = getTitleFor(content2) + fun putRequestUserData(key: Key, value: T) { + requestUserData.add(Pair(key, value)) + } + override fun getRequests(): List { return listOf(object : DiffRequestProducer { override fun getName(): String { @@ -29,7 +36,12 @@ class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffConte } override fun process(context: UserDataHolder, indicator: ProgressIndicator): DiffRequest { - return MutableChainDiffRequest(this@MutableDiffRequestChain) + val request = MutableChainDiffRequest(this@MutableDiffRequestChain) + for (it in requestUserData) { + @Suppress("UNCHECKED_CAST") + request.putUserData(it.first as Key, it.second) + } + return request } }) } @@ -64,6 +76,7 @@ class MutableDiffRequestChain(var content1: DiffContent, var content2: DiffConte } fun fireRequestUpdated() { + chain.requestUserData.clear() context.reloadDiffRequest() } } @@ -98,4 +111,4 @@ private fun getTitleFor(content: DiffContent) = if (content is FileContent) DiffRequestFactory.getInstance().getContentTitle(content.file) else null private class MutableChainDiffRequest(val chain: MutableDiffRequestChain) - : SimpleDiffRequest(null, chain.content1, chain.content2, chain.title1, chain.title2) + : SimpleDiffRequest(chain.windowTitle, chain.content1, chain.content2, chain.title1, chain.title2) From 6e740e302ee5a90861d179623c12a154e4bfb58f Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Feb 2019 14:59:23 +0100 Subject: [PATCH 063/138] move NOT_ROAMABLE_FILE from Storage to StoragePathMacros because this place is more logical --- .../jetbrains/builtInWebServer/BuiltInServerOptions.java | 9 +++------ .../src/StateStorageManagerImpl.kt | 2 +- .../testSrc/ApplicationStoreTest.kt | 4 ++-- .../src/com/intellij/ide/ui/NotRoamableUiSettings.kt | 7 ++----- .../intellij/ide/util/AppPropertiesComponentImpl.java | 5 +++-- .../intellij/openapi/application/ConfigImportHelper.java | 4 ++-- .../src/com/intellij/openapi/components/Storage.java | 4 ++-- .../intellij/openapi/components/StoragePathMacros.java | 8 +++++++- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java index ea99ee870946..8e73024baeed 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/BuiltInServerOptions.java @@ -1,12 +1,9 @@ -// 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-2019 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.builtInWebServer; import com.intellij.notification.NotificationType; import com.intellij.openapi.application.ApplicationNamesInfo; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.*; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SimpleConfigurable; import com.intellij.openapi.util.Getter; @@ -27,7 +24,7 @@ import java.util.Collections; @State( name = "BuiltInServerOptions", - storages = @Storage(Storage.NOT_ROAMABLE_FILE) + storages = @Storage(StoragePathMacros.NOT_ROAMABLE_FILE) ) public class BuiltInServerOptions implements PersistentStateComponent, Getter { public static final int DEFAULT_PORT = 63342; diff --git a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt index e71b55f5c0df..7a1e7b4dbe43 100644 --- a/platform/configuration-store-impl/src/StateStorageManagerImpl.kt +++ b/platform/configuration-store-impl/src/StateStorageManagerImpl.kt @@ -440,7 +440,7 @@ internal val Storage.path: String get() = if (value.isEmpty()) file else value internal fun getEffectiveRoamingType(roamingType: RoamingType, collapsedPath: String): RoamingType { - if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == Storage.NOT_ROAMABLE_FILE || collapsedPath == StoragePathMacros.CACHE_FILE)) { + if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == StoragePathMacros.NOT_ROAMABLE_FILE || collapsedPath == StoragePathMacros.CACHE_FILE)) { return RoamingType.DISABLED } else { diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 83c8f1185c25..e0877d35c3e8 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -294,7 +294,7 @@ internal class ApplicationStoreTest { @Test fun `other xml file as not-roamable without explicit roaming`() = runBlocking { - @State(name = "A", storages = [(Storage(value = Storage.NOT_ROAMABLE_FILE))]) + @State(name = "A", storages = [(Storage(value = StoragePathMacros.NOT_ROAMABLE_FILE))]) class AOther : A() val component = AOther() @@ -303,7 +303,7 @@ internal class ApplicationStoreTest { saveStore() - assertThat(testAppConfig.resolve(Storage.NOT_ROAMABLE_FILE)).doesNotExist() + assertThat(testAppConfig.resolve(StoragePathMacros.NOT_ROAMABLE_FILE)).doesNotExist() } private suspend fun saveStore() { diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt b/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt index 1850d4c7b4bb..b17b1dd0730d 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/NotRoamableUiSettings.kt @@ -1,10 +1,7 @@ // Copyright 2000-2019 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.ide.ui -import com.intellij.openapi.components.BaseState -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.* import com.intellij.openapi.util.Pair import com.intellij.util.ui.UIUtil import com.intellij.util.xmlb.Accessor @@ -12,7 +9,7 @@ import com.intellij.util.xmlb.SerializationFilter import com.intellij.util.xmlb.annotations.Property import java.awt.Font -@State(name = "NotRoamableUiSettings", storages = [(Storage(Storage.NOT_ROAMABLE_FILE))], reportStatistic = true) +@State(name = "NotRoamableUiSettings", storages = [(Storage(StoragePathMacros.NOT_ROAMABLE_FILE))], reportStatistic = true) class NotRoamableUiSettings : PersistentStateComponent { private var state = NotRoamableUiOptions() diff --git a/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java b/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java index 6b5c404c67dd..cb756b505a86 100644 --- a/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/util/AppPropertiesComponentImpl.java @@ -1,12 +1,13 @@ -// 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-2019 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.ide.util; import com.intellij.openapi.components.RoamingType; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; @State(name = "PropertiesComponent", storages = { - @Storage(value = Storage.NOT_ROAMABLE_FILE, roamingType = RoamingType.DISABLED), + @Storage(value = StoragePathMacros.NOT_ROAMABLE_FILE, roamingType = RoamingType.DISABLED), @Storage(value = "options.xml", roamingType = RoamingType.DISABLED, deprecated = true) }) public class AppPropertiesComponentImpl extends PropertiesComponentImpl { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java index 4460b716915a..5cd2427db024 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java @@ -6,7 +6,7 @@ import com.intellij.ide.cloudConfig.CloudConfigProvider; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.ide.startup.StartupActionScriptManager; import com.intellij.idea.Main; -import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; @@ -44,7 +44,7 @@ public class ConfigImportHelper { private static final String CONFIG = "config"; private static final String[] OPTIONS = { - OPTIONS_DIRECTORY + '/' + Storage.NOT_ROAMABLE_FILE, + OPTIONS_DIRECTORY + '/' + StoragePathMacros.NOT_ROAMABLE_FILE, OPTIONS_DIRECTORY + '/' + IDE_GENERAL_XML, OPTIONS_DIRECTORY + "/options.xml"}; private static final String BIN = "bin"; diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java index 2485f1cff967..95bf0a3f603f 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java @@ -1,7 +1,6 @@ // Copyright 2000-2019 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.openapi.components; -import com.intellij.openapi.application.PathManager; import com.intellij.util.ThreeState; import java.lang.annotation.Retention; @@ -12,7 +11,8 @@ import java.lang.annotation.RetentionPolicy; */ @Retention(RetentionPolicy.RUNTIME) public @interface Storage { - String NOT_ROAMABLE_FILE = PathManager.DEFAULT_OPTIONS_FILE; + @Deprecated + String NOT_ROAMABLE_FILE = StoragePathMacros.NOT_ROAMABLE_FILE; /** * @deprecated Use {@link #value()}. diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java index 0ee9a66fe294..1e2883dca0d0 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java @@ -1,6 +1,7 @@ -// 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-2019 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.openapi.components; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -30,6 +31,11 @@ public final class StoragePathMacros { @NotNull public static final String MODULE_FILE = "$MODULE_FILE$"; + /** + * Application level non-roamable storage. + */ + public static final String NOT_ROAMABLE_FILE = PathManager.DEFAULT_OPTIONS_FILE; + private StoragePathMacros() { } } From bebe7335d6ec39ca68d5217252e3113aa9f33124 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Mon, 4 Feb 2019 15:52:34 +0100 Subject: [PATCH 064/138] ProgressManager.checkCanceled, when a progress is started under a canceled indicator wrapper with its base indicator not canceled (readability) --- .../progress/impl/CoreProgressManager.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java index 9cacd8a6fa62..4be558605aff 100644 --- a/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java +++ b/platform/core-impl/src/com/intellij/openapi/progress/impl/CoreProgressManager.java @@ -569,13 +569,14 @@ public class CoreProgressManager extends ProgressManager implements Disposable { startBackgroundNonStandardIndicatorsPing(); } - if (thisIndicator.isCanceled()) { - threadsUnderCanceledIndicator.add(currentThread); - oneOfTheIndicatorsIsCanceled = true; - } - else if (!oneOfTheIndicatorsIsCanceled) { - threadsUnderCanceledIndicator.remove(currentThread); - } + oneOfTheIndicatorsIsCanceled |= thisIndicator.isCanceled(); + } + + if (oneOfTheIndicatorsIsCanceled) { + threadsUnderCanceledIndicator.add(currentThread); + } + else { + threadsUnderCanceledIndicator.remove(currentThread); } updateShouldCheckCanceled(); From 1febe662a8f9a86621279d30bc61ae6cacae5ef5 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 4 Feb 2019 17:58:32 +0300 Subject: [PATCH 065/138] get rid of #triggerFeatureUsed calls in goto handlers, action invocation is already recorded on the platform level --- .../navigation/actions/GotoDeclarationActionHandler.java | 2 -- .../navigation/actions/GotoDeclarationOnlyHandler.kt | 3 --- 2 files changed, 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java index 64515e2f6153..57110c01c929 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationActionHandler.java @@ -2,7 +2,6 @@ package com.intellij.codeInsight.navigation.actions; import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.find.actions.ShowUsagesAction; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; @@ -31,7 +30,6 @@ public final class GotoDeclarationActionHandler implements CodeInsightActionHand @Override public void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull PsiFile file) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration"); final PsiElement declarationElement = findDeclarationElement(project, editor); if (declarationElement == null) { GotoDeclarationOnlyHandler.INSTANCE.invoke(project, editor, file); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt index 5e9bbc2747b7..065dd3b87a75 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt @@ -7,7 +7,6 @@ import com.intellij.codeInsight.TargetElementUtil import com.intellij.codeInsight.hint.HintManager import com.intellij.codeInsight.navigation.NavigationUtil import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.* -import com.intellij.featureStatistics.FeatureUsageTracker import com.intellij.ide.util.DefaultPsiElementCellRenderer import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.DumbService @@ -23,8 +22,6 @@ object GotoDeclarationOnlyHandler : CodeInsightActionHandler { override fun startInWriteAction(): Boolean = false override fun invoke(project: Project, editor: Editor, file: PsiFile) { - FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration.only") - val dumbService = DumbService.getInstance(project) try { dumbService.isAlternativeResolveEnabled = true From 36737551ee2942236f8cd9cdb7d3ff6cb3c994c1 Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Mon, 4 Feb 2019 18:13:37 +0300 Subject: [PATCH 066/138] IDEA-206603 Some JB runtime dlls are not signed correctly --- .../intellij/build/impl/WindowsDistributionBuilder.groovy | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy index 4e171fbc30f7..d8603783ccde 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WindowsDistributionBuilder.groovy @@ -79,8 +79,11 @@ class WindowsDistributionBuilder extends OsSpecificDistributionBuilder { buildWinLauncher(it, winDistPath) } customizer.copyAdditionalFiles(buildContext, winDistPath) - new File(winDistPath, "bin").listFiles(FileFilters.filesWithExtension("exe"))?.each { - buildContext.signExeFile(it.absolutePath) + List extensions = ["exe", "dll"] + for (String extension : extensions) { + new File(winDistPath, "bin").listFiles(FileFilters.filesWithExtension(extension))?.each { + buildContext.signExeFile(it.absolutePath) + } } return winDistPath } From 1aa55e239098bc1529a2983e781a3ff0da034814 Mon Sep 17 00:00:00 2001 From: Nikolay Kuznetsov Date: Fri, 1 Feb 2019 16:55:10 +0100 Subject: [PATCH 067/138] Add extensibility to TraverseUI and related classes This allows IDEs with backends such as Rider to inject necessary waits and other code to handle non-standard settings indexing --- .../ide/ui/search/TraverseUIStarter.java | 9 ++++ .../intellij/ide/ui/search/SearchUtil.java | 28 ++++++++--- .../ide/ui/search/TraverseUIHelper.java | 49 +++++++++++++++++++ .../src/META-INF/PlatformExtensionPoints.xml | 2 + 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java diff --git a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java index eac9443d3c4d..f15718c99bb7 100644 --- a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java +++ b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java @@ -97,8 +97,14 @@ public class TraverseUIStarter extends ApplicationStarterEx { public static void startup(@NotNull final String outputPath, final boolean splitByResourcePath) throws IOException { Map> options = new LinkedHashMap<>(); try { + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeStart(); + SearchUtil.processProjectConfigurables(ProjectManager.getInstance().getDefaultProject(), options); + for (TraverseUIHelper extension1 : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension1.afterTraversal(options); + final Map roots = newHashMap(); for (SearchableConfigurable option : options.keySet()) { SearchableConfigurable configurable = option; @@ -149,6 +155,9 @@ public class TraverseUIStarter extends ApplicationStarterEx { JDOMUtil.writeDocument(new Document(entry.getValue()), output, "\n"); } + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterResultsAreSaved(); + System.out.println("Searchable options index builder completed"); } finally { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java index e36b582e8eae..417abb862ff2 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java @@ -47,7 +47,7 @@ public class SearchUtil { } private static void processConfigurables(Configurable[] configurables, Map> options) { - for (Configurable configurable : configurables) { + for (final Configurable configurable : configurables) { if (configurable instanceof SearchableConfigurable) { //ignore invisible root nodes //noinspection deprecation @@ -55,24 +55,29 @@ public class SearchUtil { continue; } + final SearchableConfigurable searchableConfigurable = (SearchableConfigurable) configurable; + Set configurableOptions = new TreeSet<>(); - options.put((SearchableConfigurable)configurable, configurableOptions); + options.put(searchableConfigurable, configurableOptions); + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeConfigurable(searchableConfigurable, configurableOptions); if (configurable instanceof MasterDetails) { final MasterDetails md = (MasterDetails)configurable; md.initUi(); - processComponent(configurable, configurableOptions, md.getMaster()); - processComponent(configurable, configurableOptions, md.getDetails().getComponent()); + processComponent(searchableConfigurable, configurableOptions, md.getMaster()); + processComponent(searchableConfigurable, configurableOptions, md.getDetails().getComponent()); } else { - processComponent(configurable, configurableOptions, configurable.createComponent()); + processComponent(searchableConfigurable, configurableOptions, configurable.createComponent()); final Configurable unwrapped = unwrapConfigurable(configurable); if (unwrapped instanceof CompositeConfigurable) { //noinspection unchecked final List children = ((CompositeConfigurable)unwrapped).getConfigurables(); for (final UnnamedConfigurable child : children) { final Set childConfigurableOptions = new TreeSet<>(); - options.put(new SearchableConfigurableAdapter((SearchableConfigurable)configurable, child), childConfigurableOptions); + options.put(new SearchableConfigurableAdapter(searchableConfigurable, child), childConfigurableOptions); if (child instanceof SearchableConfigurable) { processUILabel(((SearchableConfigurable)child).getDisplayName(), childConfigurableOptions, null); @@ -86,6 +91,9 @@ public class SearchUtil { } } } + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterConfigurable(searchableConfigurable, configurableOptions); } } } @@ -108,10 +116,16 @@ public class SearchUtil { return configurable; } - private static void processComponent(Configurable configurable, Set configurableOptions, JComponent component) { + private static void processComponent(SearchableConfigurable configurable, Set configurableOptions, JComponent component) { if (component != null) { + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.beforeComponent(configurable, component, configurableOptions); + processUILabel(configurable.getDisplayName(), configurableOptions, null); processComponent(component, configurableOptions, null); + + for (TraverseUIHelper extension : TraverseUIHelper.helperExtensionPoint.getExtensions()) + extension.afterComponent(configurable, component, configurableOptions); } } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java b/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java new file mode 100644 index 000000000000..07a110f5d682 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/TraverseUIHelper.java @@ -0,0 +1,49 @@ +package com.intellij.ide.ui.search; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.options.SearchableConfigurable; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Map; +import java.util.Set; + +public interface TraverseUIHelper { + String EP_NAME = "com.intellij.search.traverseUiHelper"; + ExtensionPointName helperExtensionPoint = ExtensionPointName.create(EP_NAME); + + /** + * Invoked before indexing SearchableConfigurables + */ + default void beforeStart() {} + + /** + * Invoked after all configurables were traversed + */ + default void afterTraversal(@NotNull Map> options) {} + + /** + * Invoked after indexing all SearchableConfigurables and results are saved + */ + default void afterResultsAreSaved() {} + + /** + * Invoked before indexing a SearchableConfigurable + */ + default void beforeConfigurable(@NotNull SearchableConfigurable configurable, @NotNull Set options) {} + + /** + * Invoked after indexing a SearchableConfigurable + */ + default void afterConfigurable(@NotNull SearchableConfigurable configurable, @NotNull Set options) {} + + /** + * Invoked before indexing the root component of a SearchableConfigurable + */ + default void beforeComponent(@NotNull SearchableConfigurable configurable, @NotNull JComponent component, @NotNull Set options) {} + + /** + * Invoked after indexing the root component of a SearchableConfigurable + */ + default void afterComponent(@NotNull SearchableConfigurable configurable, @NotNull JComponent component, @NotNull Set options) {} +} \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index b1738a0eeaa7..ee1b4c01565b 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -336,5 +336,7 @@ + + From c96e2cc6efaf5d5c0a789be72bc6375b3cb47b86 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 16:35:30 +0100 Subject: [PATCH 068/138] FUS: add action to test whitelist --- .../TestParseEventLogWhitelistAction.java | 34 +++ .../TestParseEventLogWhitelistDialog.form | 83 +++++++ .../TestParseEventLogWhitelistDialog.java | 184 ++++++++++++++ .../FeatureStatisticsWhitelistTest.kt | 224 ++++++++++++++++++ resources/src/idea/RichPlatformActions.xml | 5 + 5 files changed, 530 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java create mode 100644 platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form create mode 100644 platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java new file mode 100644 index 000000000000..04cd1dc05285 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistAction.java @@ -0,0 +1,34 @@ +// Copyright 2000-2019 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.internal.statistic.actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.application.ex.ApplicationManagerEx; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class TestParseEventLogWhitelistAction extends DumbAwareAction { + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final Project project = e.getProject(); + if (project != null) { + new TestParseEventLogWhitelistDialog(project, e.getData(CommonDataKeys.EDITOR)).show(); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + boolean enabled = isEnabled(e.getProject()); + e.getPresentation().setEnabledAndVisible(enabled); + if (enabled && e.getData(CommonDataKeys.EDITOR) == null) { + e.getPresentation().setEnabled(false); + } + } + + private static boolean isEnabled(@Nullable Project project) { + return project != null && ApplicationManagerEx.getApplicationEx().isInternal(); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form new file mode 100644 index 000000000000..76fc305af526 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.form @@ -0,0 +1,83 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java new file mode 100644 index 000000000000..7503708172ea --- /dev/null +++ b/platform/lang-impl/src/com/intellij/internal/statistic/actions/TestParseEventLogWhitelistDialog.java @@ -0,0 +1,184 @@ +// Copyright 2000-2019 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.internal.statistic.actions; + +import com.intellij.internal.statistic.eventLog.*; +import com.intellij.internal.statistic.service.fus.FUStatisticsWhiteListGroupsService; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.BuildNumber; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.testFramework.LightVirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +public class TestParseEventLogWhitelistDialog extends DialogWrapper { + private static final Logger LOG = Logger.getInstance(TestParseEventLogWhitelistDialog.class); + + private static final int IN_DIVIDER_LOCATION = 650; + private static final int IN_OUT_DIVIDER_LOCATION = 500; + private JPanel myMainPanel; + private JPanel myWhitelistPanel; + private JEditorPane myEventLogPanel; + private JSplitPane myInputDataSplitPane; + private JSplitPane myInputOutputSplitPane; + private JEditorPane myResultPane; + + private final Project myProject; + private final EditorEx myEditor; + + protected TestParseEventLogWhitelistDialog(@NotNull Project project, @Nullable Editor selectedEditor) { + super(project); + myProject = project; + setOKButtonText("&Filter Event Log"); + setCancelButtonText("&Close"); + Disposer.register(myProject, getDisposable()); + VirtualFile selectedFile = selectedEditor == null ? null : FileDocumentManager.getInstance().getFile(selectedEditor.getDocument()); + setTitle(selectedFile == null ? "Event Log Filter" : "Event Log Filter by: " + selectedFile.getName()); + myEditor = initEditor(selectedEditor); + myEditor.getSettings().setLineMarkerAreaShown(false); + + init(); + if (selectedEditor != null) { + doOKAction(); + + ApplicationManager.getApplication().invokeLater(() -> { + IdeFocusManager.getGlobalInstance() + .doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true)); + myEditor.getCaretModel().moveToOffset(selectedEditor.getCaretModel().getOffset()); + myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + }, ModalityState.stateForComponent(myMainPanel)); + } + } + + @NotNull + private EditorEx initEditor(@Nullable Editor selectedEditor) { + if (selectedEditor != null) { + return (EditorEx)EditorFactory.getInstance().createEditor(selectedEditor.getDocument(), myProject); + } + else { + Document document = EditorFactory.getInstance().createDocument(StringUtil.notNullize("{}")); + EditorEx editor = (EditorEx)EditorFactory.getInstance().createEditor(document, myProject); + editor.getSelectionModel().setSelection(0, document.getTextLength()); + return editor; + } + } + + @Override + protected void init() { + configEditorPanel(myProject, myWhitelistPanel, myEditor); + + myInputDataSplitPane.setDividerLocation(IN_DIVIDER_LOCATION); + myInputOutputSplitPane.setDividerLocation(IN_OUT_DIVIDER_LOCATION); + super.init(); + } + + private static void configEditorPanel(@NotNull Project project, @NotNull JPanel panel, @NotNull EditorEx editor) { + panel.setLayout(new BorderLayout()); + panel.add(editor.getComponent(), BorderLayout.CENTER); + + editor.getSettings().setFoldingOutlineShown(false); + final FileType fileType = FileTypeManager.getInstance().findFileTypeByName("JSON"); + final LightVirtualFile lightFile = new LightVirtualFile("Dummy.json", fileType, ""); + + EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(project, lightFile); + try { + editor.setHighlighter(highlighter); + } + catch (Throwable e) { + LOG.warn(e); + } + } + + @Override + @NotNull + protected String getDimensionServiceKey() { + return TestParseEventLogWhitelistDialog.class.getCanonicalName(); + } + + @SuppressWarnings("TestOnlyProblems") + @Override + protected void doOKAction() { + myEditor.getSelectionModel().removeSelection(); + updateOutputText(""); + + final BuildNumber build = BuildNumber.fromString(EventLogConfiguration.INSTANCE.getBuild()); + final Set groups = FUStatisticsWhiteListGroupsService.parseApprovedGroups(myEditor.getDocument().getText(), build); + try { + final String parsed = parseLogAndFilter(new LogEventWhitelistFilter(groups), myEventLogPanel.getText()); + updateOutputText(parsed.trim()); + } + catch (IOException | ParseEventLogWhitelistException e) { + Messages.showErrorDialog(myProject, e.getMessage(), "Failed Applying Whitelist to Event Log"); + } + } + + private void updateOutputText(@NotNull String text) { + myResultPane.setText(text); + } + + @NotNull + private static String parseLogAndFilter(@NotNull LogEventFilter filter, @NotNull String text) + throws IOException, ParseEventLogWhitelistException { + final File log = FileUtil.createTempFile("feature-event-log", ".log"); + try { + FileUtil.writeToFile(log, text); + final LogEventRecordRequest request = LogEventRecordRequest.Companion.create(log, filter, true); + if (request == null) { + throw new ParseEventLogWhitelistException("Failed parsing event log"); + } + return LogEventSerializer.INSTANCE.toString(request); + } + finally { + FileUtil.delete(log); + } + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myMainPanel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myEventLogPanel; + } + + @Override + public void dispose() { + if (!myEditor.isDisposed()) { + EditorFactory.getInstance().releaseEditor(myEditor); + } + super.dispose(); + } + + public static class ParseEventLogWhitelistException extends Exception { + public ParseEventLogWhitelistException(String s) { + super(s); + } + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt index 3fb114def4a5..a8799b3e3732 100644 --- a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt @@ -672,6 +672,230 @@ class FeatureStatisticsWhitelistTest { doTest(content, "183.2495", "test.group.id") } + @Test + fun `with from snapshot and build later is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495", "test.group.id") + } + + @Test + fun `with from snapshot and build later with bugfix update is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.245", "test.group.id") + } + + @Test + fun `with from snapshot and build earlier is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "191.0" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495") + } + + @Test + fun `with from equals to build is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495", "test.group.id") + } + + @Test + fun `with from middle number equals to build is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.0", "test.group.id") + } + + @Test + fun `with from middle number equals to build and last is bigger is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495.12", "test.group.id") + } + + @Test + fun `with build middle number equals to from and last is bigger is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.1495") + } + + @Test + fun `with build middle number equals to to is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4885") + } + + @Test + fun `with build middle number equals to to and last is bigger is not accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4885.35") + } + + @Test + fun `with build middle number smaller then to is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4884.35", "test.group.id") + } + + @Test + fun `with build middle number smaller then to and have two numbers is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "183.1495.12", + "to": "183.4885" + }], + "context" : { + } + }] +} + """ + doTest(content, "183.4884", "test.group.id") + } + @Test fun `snapshot builds major greater than from is accepted`() { val content = """ diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml index 5bff857de91c..d350b3c18185 100644 --- a/resources/src/idea/RichPlatformActions.xml +++ b/resources/src/idea/RichPlatformActions.xml @@ -172,6 +172,11 @@ + + + + From 650999a046665d4121eca43c20433e72d4368dea Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 16:45:31 +0100 Subject: [PATCH 069/138] FUS: add more tests for whitelist --- .../FeatureStatisticsWhitelistTest.kt | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt index a8799b3e3732..f7fb5249431e 100644 --- a/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/internal/statistics/FeatureStatisticsWhitelistTest.kt @@ -17,6 +17,53 @@ class FeatureStatisticsWhitelistTest { } } + @Test + fun `with build and group version is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "173.4284.118" + }], + "versions" : [ { + "from" : "3", + "to" : "5" + }], + "context" : { + } + }] +} + """ + doTest(content, "IU-173.4284.118", "test.group.id") + } + + @Test + fun `with build and from group version is accepted`() { + val content = """ +{ + "groups" : [{ + "id" : "test.group.id", + "title" : "Test Group", + "description" : "Test group description", + "type" : "counter", + "builds" : [ { + "from" : "173.4284.118" + }], + "versions" : [ { + "from" : "3" + }], + "context" : { + } + }] +} + """ + doTest(content, "IU-173.4284.118", "test.group.id") + } + @Test fun `with equal build than from is accepted`() { val content = """ From 428891240ba1ea11b072ae83cf815c2806971283 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Mon, 4 Feb 2019 18:48:19 +0300 Subject: [PATCH 070/138] Gradle: set `idea.active` and `idea.version` system properties for all gradle invocations --- .../service/execution/GradleExecutionHelper.java | 15 +++++++++++++-- .../service/project/GradleProjectResolver.java | 7 +------ .../gradle/tooling/internal/init/init.gradle | 1 - .../tooling/internal/init/testFilterInit.gradle | 1 - 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java index b1b81730819c..85517ef367eb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/execution/GradleExecutionHelper.java @@ -5,6 +5,8 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationInfoEx; +import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.ExternalSystemException; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; @@ -137,17 +139,21 @@ public class GradleExecutionHelper { } } + List filteredArgs = ContainerUtil.newArrayList(); if (!settings.getArguments().isEmpty()) { String loggableArgs = StringUtil.join(obfuscatePasswordParameters(settings.getArguments()), " "); LOG.info("Passing command-line args to Gradle Tooling API: " + loggableArgs); // filter nulls and empty strings - List filteredArgs = ContainerUtil.mapNotNull(settings.getArguments(), s -> StringUtil.isEmpty(s) ? null : s); + filteredArgs.addAll(ContainerUtil.mapNotNull(settings.getArguments(), s -> StringUtil.isEmpty(s) ? null : s)); // TODO remove this replacement when --tests option will become available for tooling API replaceTestCommandOptionWithInitScript(filteredArgs); - operation.withArguments(ArrayUtil.toStringArray(filteredArgs)); } + filteredArgs.add("-Didea.active=true"); + filteredArgs.add("-Didea.version=" + getIdeaVersion()); + operation.withArguments(ArrayUtil.toStringArray(filteredArgs)); + setupEnvironment(operation, settings, gradleVersion, id, listener); final String javaHome = settings.getJavaHome(); @@ -779,4 +785,9 @@ public class GradleExecutionHelper { settings.withArguments(commandLineArgs).withVmOptions(extraJvmArgs); prepare(operation, id, settings, listener, connection, standardOutput, standardError); } + + private static String getIdeaVersion() { + ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance(); + return appInfo.getMajorVersion() + "." + appInfo.getMinorVersion(); + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index aefa12ffce08..df96af0e272e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -198,7 +198,7 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver previewLightWeightToolingModels = ContainerUtil.set(ExternalProjectPreview.class, GradleBuild.class); @@ -792,9 +792,4 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver=0 boolean skipExecution From fca64e9c50367d10d521667d51d133fc4396104b Mon Sep 17 00:00:00 2001 From: Shaverdova Elena Date: Mon, 4 Feb 2019 16:12:46 +0100 Subject: [PATCH 071/138] Report actions with id from editor's panel in actions statistic group --- .../src/com/intellij/ui/EditorNotificationPanel.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java index 4ad9c87ef258..3aeeb12e9a66 100644 --- a/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java +++ b/platform/platform-api/src/com/intellij/ui/EditorNotificationPanel.java @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorBundle; import com.intellij.openapi.editor.colors.ColorKey; @@ -132,16 +133,24 @@ public class EditorNotificationPanel extends JPanel implements IntentionActionPr protected void executeAction(final String actionId) { final AnAction action = ActionManager.getInstance().getAction(actionId); - final AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, + final AnActionEvent event = AnActionEvent.createFromAnAction(action, null, getActionPlace(), DataManager.getInstance().getDataContext(this)); action.beforeActionPerformedUpdate(event); action.update(event); if (event.getPresentation().isEnabled() && event.getPresentation().isVisible()) { + ActionManagerEx actionManager = ActionManagerEx.getInstanceEx(); + actionManager.fireBeforeActionPerformed(action, event.getDataContext(), event); action.actionPerformed(event); + actionManager.fireAfterActionPerformed(action, event.getDataContext(), event); } } + @NotNull + protected String getActionPlace() { + return ActionPlaces.UNKNOWN; + } + @Nullable @Override public IntentionActionWithOptions getIntentionAction() { From 4f8208f3080cb3dda42e29fb0f84f7badb3d372a Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Feb 2019 14:38:51 +0100 Subject: [PATCH 072/138] EditorNotifications: shorten code and make it async in tests by using ReadAction.nonBlocking --- .../impl/SdkSetupNotificationTestBase.java | 2 + .../intellij/ui/EditorNotificationsImpl.java | 117 ++++++------------ 2 files changed, 38 insertions(+), 81 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java index e233c3ab6a94..f97f17bf1960 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/impl/SdkSetupNotificationTestBase.java @@ -15,6 +15,7 @@ import com.intellij.psi.PsiFile; import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.ui.EditorNotificationPanel; +import com.intellij.ui.EditorNotificationsImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,6 +59,7 @@ public abstract class SdkSetupNotificationTestBase extends JavaCodeInsightFixtur final PsiFile psiFile = myFixture.configureByText(name, text); final FileEditor[] editors = FileEditorManagerEx.getInstanceEx(getProject()).openFile(psiFile.getVirtualFile(), true); assertSize(1, editors); + EditorNotificationsImpl.completeAsyncTasks(); return editors[0].getUserData(SdkSetupNotificationProvider.KEY); } diff --git a/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java b/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java index b436c5678340..f36ff9ee04e6 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorNotificationsImpl.java @@ -2,18 +2,14 @@ package com.intellij.ui; import com.intellij.ProjectTopics; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.application.impl.NonBlockingReadActionImpl; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; -import com.intellij.openapi.progress.util.ProgressIndicatorUtils; -import com.intellij.openapi.progress.util.ReadTask; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; @@ -25,7 +21,6 @@ import com.intellij.psi.PsiFile; import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; -import com.intellij.reference.SoftReference; import com.intellij.util.SmartList; import com.intellij.util.concurrency.SequentialTaskExecutor; import com.intellij.util.containers.ContainerUtil; @@ -35,9 +30,10 @@ import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; +import org.jetbrains.concurrency.CancellablePromise; import javax.swing.*; -import java.lang.ref.WeakReference; import java.util.List; import java.util.concurrent.ExecutorService; @@ -45,7 +41,7 @@ import java.util.concurrent.ExecutorService; * @author peter */ public class EditorNotificationsImpl extends EditorNotifications { - private static final Key> CURRENT_UPDATES = Key.create("CURRENT_UPDATES"); + private final Key> CURRENT_UPDATE = Key.create("EditorNotifications update"); // non-static, per-project private static final ExecutorService ourExecutor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor( "EditorNotificationsImpl Pool"); private final MergingUpdateQueue myUpdateMerger; @@ -83,89 +79,42 @@ public class EditorNotificationsImpl extends EditorNotifications { @Override public void updateNotifications(@NotNull final VirtualFile file) { UIUtil.invokeLaterIfNeeded(() -> { - ProgressIndicator indicator = getCurrentProgress(file); - if (indicator != null) { - indicator.cancel(); - } - file.putUserData(CURRENT_UPDATES, null); - if (myProject.isDisposed() || !file.isValid()) { return; } - indicator = new ProgressIndicatorBase(); - final ReadTask task = createTask(indicator, file); - if (task == null) return; + CancellablePromise prev = file.getUserData(CURRENT_UPDATE); + if (prev != null) { + prev.cancel(); + } - file.putUserData(CURRENT_UPDATES, new WeakReference<>(indicator)); - if (ApplicationManager.getApplication().isUnitTestMode()) { - ReadTask.Continuation continuation = task.performInReadAction(indicator); - if (continuation != null) { - continuation.getAction().run(); - } - } - else { - ProgressIndicatorUtils.scheduleWithWriteActionPriority(indicator, ourExecutor, task); - } + CancellablePromise> promise = ReadAction. + nonBlocking(() -> calcNotificationUpdates(file)). + expireWhen(() -> !file.isValid() || myProject.isDisposed()). + finishOnUiThread(ModalityState.any(), updates -> { + for (Runnable update : updates) { + update.run(); + } + }). + submit(ourExecutor); + file.putUserData(CURRENT_UPDATE, promise); + promise.onProcessed(__ -> file.putUserData(CURRENT_UPDATE, null)); }); } - @Nullable - private ReadTask createTask(@NotNull final ProgressIndicator indicator, @NotNull final VirtualFile file) { + @NotNull + private List calcNotificationUpdates(@NotNull VirtualFile file) { List editors = ContainerUtil.filter(FileEditorManager.getInstance(myProject).getAllEditors(file), editor -> !(editor instanceof TextEditor) || AsyncEditorLoader.isEditorLoaded(((TextEditor)editor).getEditor())); - if (editors.isEmpty()) return null; - - return new ReadTask() { - private boolean isOutdated() { - if (myProject.isDisposed() || !file.isValid() || indicator != getCurrentProgress(file)) { - return true; - } - - for (FileEditor editor : editors) { - if (!editor.isValid()) { - return true; - } - } - - return false; + List providers = DumbService.getDumbAwareExtensions(myProject, EXTENSION_POINT_NAME); + List updates = new SmartList<>(); + for (FileEditor editor : editors) { + for (Provider provider : providers) { + JComponent component = provider.createNotificationPanel(file, editor); + updates.add(() -> updateNotification(editor, provider.getKey(), component)); } - - @Nullable - @Override - public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException { - if (isOutdated()) return null; - - final List providers = DumbService.getDumbAwareExtensions(myProject, EXTENSION_POINT_NAME); - final List updates = new SmartList<>(); - for (final FileEditor editor : editors) { - for (final Provider provider : providers) { - final JComponent component = provider.createNotificationPanel(file, editor); - updates.add(() -> updateNotification(editor, provider.getKey(), component)); - } - } - - return new Continuation(() -> { - if (!isOutdated()) { - file.putUserData(CURRENT_UPDATES, null); - for (Runnable update : updates) { - update.run(); - } - } - }, ModalityState.any()); - } - - @Override - public void onCanceled(@NotNull ProgressIndicator ignored) { - if (getCurrentProgress(file) == indicator) { - updateNotifications(file); - } - } - }; - } - - private static ProgressIndicator getCurrentProgress(VirtualFile file) { - return SoftReference.dereference(file.getUserData(CURRENT_UPDATES)); + } + return updates; } private void updateNotification(@NotNull FileEditor editor, @NotNull Key key, @Nullable JComponent component) { @@ -220,4 +169,10 @@ public class EditorNotificationsImpl extends EditorNotifications { return null; } } + + @TestOnly + public static void completeAsyncTasks() { + NonBlockingReadActionImpl.completeAsyncTasks(); + } + } From 7f69478dd0e3e63fb0bfb163ee7de80784be115b Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 17:44:13 +0300 Subject: [PATCH 073/138] IDEA-206547: workaround for changed behaviour in JDK 11 --- .../src/com/intellij/openapi/ui/MasterDetailsComponent.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java index 130ce71d20a4..c43ef5bd384a 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java @@ -815,8 +815,9 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom @NotNull public String getDisplayName() { final NamedConfigurable configurable = (NamedConfigurable)getUserObject(); - LOG.assertTrue(configurable != null, "Tree was already disposed"); - return configurable.getDisplayName(); + if (configurable != null) return configurable.getDisplayName(); + LOG.debug("Tree was already disposed"); // workaround for IDEA-206547 + return "DISPOSED"; } public NamedConfigurable getConfigurable() { From 47be99144ab7f2d50f21ca554c340c9b38944973 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 19:03:42 +0300 Subject: [PATCH 074/138] IDEA-206436: Memory hogging in Diagrams + Structure tool window + Zoom In/Out --- .../intellij/ide/impl/StructureViewWrapperImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java index 9b93c4773560..ca1b2e67be4c 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.java @@ -124,9 +124,14 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl if (BitUtil.isSet(e.getChangeFlags(), HierarchyEvent.DISPLAYABILITY_CHANGED)) { boolean visible = myToolWindow.isVisible(); LOG.debug("displayability changed: " + visible); - if (!visible) return; // do nothing on hide - loggedRun("update file", StructureViewWrapperImpl.this::checkUpdate); - scheduleRebuild(); + if (visible) { + loggedRun("update file", StructureViewWrapperImpl.this::checkUpdate); + scheduleRebuild(); + } + else if (!myProject.isDisposed()) { + myFile = null; + loggedRun("clear a structure on hide", StructureViewWrapperImpl.this::rebuild); + } } } }); From 8d9aefea413498820132b38d6d69087e85039f2b Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 19:05:01 +0300 Subject: [PATCH 075/138] IDEA-206473: Sorting Directories by length of the Dir-Name --- .../src/com/intellij/ide/scopeView/ScopeViewTreeModel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java index ad1259fbe01f..e07bc6b99c2d 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java @@ -650,7 +650,9 @@ public final class ScopeViewTreeModel extends BaseTreeModel im attributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; } } - presentation.addText(title != null ? title : toString(), attributes); + String text = title != null ? title : toString(); + presentation.setPresentableText(text); + presentation.addText(text, attributes); Icon icon = getIcon(); if (icon == null && file.isValid()) { icon = file.isDirectory() From 17966c974e662acc2304f2125b390c3772f75953 Mon Sep 17 00:00:00 2001 From: Mikhail Sokolov Date: Mon, 4 Feb 2019 19:03:59 +0300 Subject: [PATCH 076/138] another staistics fix --- .../intellij/ide/actions/GotoActionAction.java | 2 +- .../intellij/ide/actions/GotoActionBase.java | 18 +++++++++++++----- .../intellij/ide/actions/GotoClassAction.java | 2 +- .../intellij/ide/actions/GotoFileAction.java | 2 +- .../intellij/ide/actions/GotoSymbolAction.java | 2 +- .../ide/actions/SearchEverywhereAction.java | 3 ++- .../searcheverywhere/SearchEverywhereUI.java | 15 +++++++++++---- .../SearchEverywhereUsageTriggerCollector.java | 15 +++++++++++++++ 8 files changed, 45 insertions(+), 14 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index 90da9fd9a37a..3ed3f2a90235 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -55,7 +55,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere") && e.getProject() != null) { - showInSearchEverywherePopup(ActionSearchEverywhereContributor.class.getSimpleName(), e, false); + showInSearchEverywherePopup(ActionSearchEverywhereContributor.class.getSimpleName(), e, false, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index 452cc3520593..9ed82f65806c 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -325,6 +325,10 @@ public abstract class GotoActionBase extends AnAction { } protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt, boolean useEditorSelection) { + showInSearchEverywherePopup(searchProviderID, evnt, useEditorSelection, false); + } + + protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt, boolean useEditorSelection, boolean sendStatistics) { SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); @@ -334,15 +338,19 @@ public abstract class GotoActionBase extends AnAction { } else { seManager.setShownContributor(searchProviderID); - String shortcut = KeymapUtil.getEventCallerKeystrokeText(evnt); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, shortcut); - SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); + if (sendStatistics) { + String shortcut = KeymapUtil.getEventCallerKeystrokeText(evnt); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, shortcut); + SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); + } } return; } - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); - SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); + if (sendStatistics) { + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); + SearchEverywhereUsageTriggerCollector.trigger(evnt.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); + } IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); String searchText = StringUtil.nullize(getInitialText(useEditorSelection, evnt).first); seManager.show(searchProviderID, searchText, evnt); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 5af1a1f98195..1dc87d6d6995 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -51,7 +51,7 @@ public class GotoClassAction extends GotoActionBase implements DumbAware { if (!DumbService.getInstance(project).isDumb()) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index e2d72be2fdf5..d26cf90d7122 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -56,7 +56,7 @@ public class GotoFileAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index cd73019b2da2..959df33ccab8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -18,7 +18,7 @@ public class GotoSymbolAction extends GotoActionBase { @Override public void actionPerformed(@NotNull AnActionEvent e) { if (Registry.is("new.search.everywhere")) { - showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e, true); + showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e, true, true); } else { super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 38bcba0edb27..236b6a3e4251 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -584,7 +584,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return; } - SearchEverywhereUsageTriggerCollector.trigger(e.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, FUSUsageContext.create(searchProviderID)); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(searchProviderID, null); + SearchEverywhereUsageTriggerCollector.trigger(e.getProject(), SearchEverywhereUsageTriggerCollector.DIALOG_OPEN, context); IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); String text = GotoActionBase.getInitialTextForNavigation(e.getData(CommonDataKeys.EDITOR)); seManager.show(searchProviderID, text, e); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java index 803d247b7161..ce81120898b8 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -445,7 +445,10 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic @Override public void mousePressed(MouseEvent e) { switchToTab(SETab.this); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(getID(), "mouseClick"); + String reportableID = getContributor() + .map(SearchEverywhereUsageTriggerCollector::getReportableContributorID) + .orElse(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(reportableID, "mouseClick"); featureTriggered(SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); } }); @@ -750,9 +753,12 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic } private void triggerTabSwitched(AnActionEvent e) { - String selectedContributorID = getSelectedContributorID(); String shortcut = getEventShortcut(e).orElse(null); - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(selectedContributorID, shortcut); + String id = mySelectedTab.getContributor() + .map(SearchEverywhereUsageTriggerCollector::getReportableContributorID) + .orElse(SearchEverywhereManagerImpl.ALL_CONTRIBUTORS_GROUP_ID); + + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(id, shortcut); featureTriggered(SearchEverywhereUsageTriggerCollector.TAB_SWITCHED, context); } @@ -839,7 +845,8 @@ public class SearchEverywhereUI extends BigPopupUI implements DataProvider, Quic SearchEverywhereContributor contributor = myListModel.getContributorForIndex(i); Object value = myListModel.getElementAt(i); if (isAllTab) { - FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(contributor.getSearchProviderId(), null); + String reportableContributorID = SearchEverywhereUsageTriggerCollector.getReportableContributorID(contributor); + FUSUsageContext context = SearchEverywhereUsageTriggerCollector.createContext(reportableContributorID, null); featureTriggered(SearchEverywhereUsageTriggerCollector.CONTRIBUTOR_ITEM_SELECTED, context); } closePopup |= contributor.processSelectedItem(value, modifiers, searchText); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java index 84600bbb090c..666c2307eb8f 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/statistics/SearchEverywhereUsageTriggerCollector.java @@ -1,15 +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. package com.intellij.ide.actions.searcheverywhere.statistics; +import com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor; import com.intellij.internal.statistic.eventLog.FeatureUsageData; import com.intellij.internal.statistic.service.fus.collectors.FUCounterUsageLogger; import com.intellij.internal.statistic.service.fus.collectors.FUSUsageContext; +import com.intellij.internal.statistic.utils.PluginInfo; +import com.intellij.internal.statistic.utils.PluginInfoDetectorKt; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class SearchEverywhereUsageTriggerCollector { + // this string will be used as ID for contributors from private + // plugins that mustn't be sent in statistics + private static final String NOT_REPORTABLE_CONTRIBUTOR_ID = "nonPublicContributor"; + public static final String DIALOG_OPEN = "dialogOpen"; public static final String TAB_SWITCHED = "tabSwitched"; public static final String GROUP_NAVIGATE = "navigateThroughGroups"; @@ -26,4 +34,11 @@ public class SearchEverywhereUsageTriggerCollector { public static FUSUsageContext createContext(@Nullable String contributorID, @Nullable String shortcut) { return FUSUsageContext.create(contributorID, shortcut); } + + @NotNull + public static String getReportableContributorID(@NotNull SearchEverywhereContributor contributor) { + Class clazz = contributor.getClass(); + PluginInfo pluginInfo = PluginInfoDetectorKt.getPluginInfo(clazz); + return pluginInfo.isSafeToReport() ? contributor.getSearchProviderId() : NOT_REPORTABLE_CONTRIBUTOR_ID; + } } From 93aff7028f0d9ceb0b8bdde675e49255d440567c Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Feb 2019 18:27:50 +0300 Subject: [PATCH 077/138] Java: Simplify highlighting of duplicate values and branches in enhanced 'switch' (IDEA-202629) --- .../codeInspection/DuplicateBranchesInSwitchInspection.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java index 813ccbef05d1..7dd92fa566d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java @@ -467,7 +467,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @NotNull protected final T myLabel; @NotNull protected final PsiStatement[] myStatements; @NotNull protected final String[] myCommentTexts; - protected final boolean myInExpression; private final boolean myIsDefault; private DuplicatesFinder myFinder; @@ -478,7 +477,6 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { myLabel = labels[0]; myStatements = statements; myCommentTexts = commentTexts; - myInExpression = PsiTreeUtil.getParentOfType(labels[0], PsiSwitchBlock.class) instanceof PsiSwitchExpression; myIsDefault = ContainerUtil.find(labels, PsiSwitchLabelStatementBase::isDefaultCase) != null; } From d3627f4d008630346f224c9501d3813ee2ebab06 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Mon, 4 Feb 2019 19:12:09 +0300 Subject: [PATCH 078/138] look for inner and anonymous classes in non-source files --- .../com/intellij/debugger/engine/PositionManagerImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index af17d6c4b073..1a372e34aafa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -1,4 +1,4 @@ -// 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-2019 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.engine; import com.intellij.debugger.MultiRequestPositionManager; @@ -337,8 +337,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio PsiFile[] files = FilenameIndex.getFilesByName(project, refType.sourceName(), GlobalSearchScope.allScope(project)); for (PsiFile file : files) { if (file instanceof PsiJavaFile) { - for (PsiClass cls : ((PsiJavaFile)file).getClasses()) { - if (StringUtil.equals(originalQName, cls.getQualifiedName())) { + for (PsiClass cls : PsiTreeUtil.findChildrenOfAnyType(file, PsiClass.class)) { + if (StringUtil.equals(originalQName, JVMNameUtil.getClassVMName(cls))) { return file; } } From 66194ae855e6b00edc2dac426b8a68a2f8b776b2 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Mon, 4 Feb 2019 17:33:39 +0300 Subject: [PATCH 079/138] Simplify reading environment variables to override (IDEA-CR-42741) --- plugins/terminal/resources/.zshrc | 4 +--- plugins/terminal/resources/jediterm-bash.in | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/plugins/terminal/resources/.zshrc b/plugins/terminal/resources/.zshrc index adbc7f7bc754..7829d450d948 100644 --- a/plugins/terminal/resources/.zshrc +++ b/plugins/terminal/resources/.zshrc @@ -47,15 +47,13 @@ then fi function override_jb_variables { - env | while read VARIABLE + env | while IFS="=" read NAME VALUE do - NAME=${VARIABLE%%=*} if [[ $NAME = '_INTELLIJ_FORCE_SET_'* ]] then NEW_NAME=${NAME:20} if [ -n "$NEW_NAME" ] then - VALUE=${VARIABLE#*=} export "$NEW_NAME"="$VALUE" fi fi diff --git a/plugins/terminal/resources/jediterm-bash.in b/plugins/terminal/resources/jediterm-bash.in index 78eacb5b3b86..e8cb2c66dfaf 100644 --- a/plugins/terminal/resources/jediterm-bash.in +++ b/plugins/terminal/resources/jediterm-bash.in @@ -32,15 +32,13 @@ function load_interactive_configs { } function override_jb_variables { - env | while read VARIABLE + env | while IFS="=" read NAME VALUE do - NAME=${VARIABLE%%=*} if [[ $NAME = '_INTELLIJ_FORCE_SET_'* ]] then NEW_NAME=${NAME:20} if [ -n "$NEW_NAME" ] then - VALUE=${VARIABLE#*=} export "$NEW_NAME"="$VALUE" fi fi From cfb8ff402693a6544e726cfdb17dc2b56e3aa72c Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Mon, 4 Feb 2019 18:58:48 +0300 Subject: [PATCH 080/138] remove unused libraries somewhere in VCS --- .../jetbrains/intellij/build/CommunityLibraryLicenses.groovy | 2 -- plugins/git4idea/intellij.vcs.git.iml | 4 ---- plugins/github/intellij.vcs.github.iml | 1 - plugins/svn4idea/intellij.vcs.svn.iml | 4 ---- 4 files changed, 11 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy index f1e019603cd9..f66928c07f19 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -72,8 +72,6 @@ class CommunityLibraryLicenses { new LibraryLicense(name: "Apache Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html"), - new LibraryLicense(name: "Apache Axis wstx-asl", libraryName: "wstx-asl", version: "1.4", license: "Apache 2.0", - url: "http://ws.apache.org/axis/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html"), new LibraryLicense(name: "Apache Commons BeanUtils", libraryName: "commons-beanutils.jar", version: "1.6", license: "Apache 2.0", url: "http://commons.apache.org/beanutils/"), diff --git a/plugins/git4idea/intellij.vcs.git.iml b/plugins/git4idea/intellij.vcs.git.iml index 116eac1deb0e..2452eedd41f5 100644 --- a/plugins/git4idea/intellij.vcs.git.iml +++ b/plugins/git4idea/intellij.vcs.git.iml @@ -26,10 +26,7 @@ - - - @@ -37,7 +34,6 @@ - diff --git a/plugins/github/intellij.vcs.github.iml b/plugins/github/intellij.vcs.github.iml index 532846ee7438..4cdc90754f9f 100644 --- a/plugins/github/intellij.vcs.github.iml +++ b/plugins/github/intellij.vcs.github.iml @@ -31,7 +31,6 @@ - \ No newline at end of file diff --git a/plugins/svn4idea/intellij.vcs.svn.iml b/plugins/svn4idea/intellij.vcs.svn.iml index 6b41f80a9095..da2cc4a34896 100644 --- a/plugins/svn4idea/intellij.vcs.svn.iml +++ b/plugins/svn4idea/intellij.vcs.svn.iml @@ -10,15 +10,11 @@ - - - - From 4a0df681da8916dad2e10c5908d2372d0017fa5f Mon Sep 17 00:00:00 2001 From: Alexander Bubenchikov Date: Mon, 4 Feb 2019 19:52:42 +0300 Subject: [PATCH 081/138] IDEA-183383 - fix libraries exclude --- .../intellij.maven.server.m3.common.iml | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml b/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml index ab719393f7cf..f8537e3cc3e7 100644 --- a/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml +++ b/plugins/maven/maven3-server-common/intellij.maven.server.m3.common.iml @@ -12,7 +12,12 @@ - + + + + + + @@ -22,7 +27,19 @@ - + + + + + + + + + + + + + @@ -32,7 +49,11 @@ - + + + + + From 2807ef93b55a7b3991920468e1f2e551e12e20dd Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Mon, 4 Feb 2019 17:17:27 +0300 Subject: [PATCH 082/138] vcs: move VcsVFSListener to vcs-impl --- .../src/com/intellij/openapi/vcs/VcsVFSListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename platform/{vcs-api => vcs-impl}/src/com/intellij/openapi/vcs/VcsVFSListener.java (99%) diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java similarity index 99% rename from platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java rename to platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java index b85f43ba5ae6..790507de5101 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -1,4 +1,4 @@ -// 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-2019 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.openapi.vcs; From f52fb5bf260f470b3789c3ebc1bd12090c7a038e Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Tue, 27 Nov 2018 13:15:32 +0300 Subject: [PATCH 083/138] vcs: refactor: extract generic FilesProcessorWithNotification component --- .../src/META-INF/VcsExtensions.xml | 2 - ...ilesProcessor.java => FilesProcessor.java} | 4 +- .../vcs/FilesProcessorWithNotificationImpl.kt | 152 ++++++++++++++++++ .../ProjectConfigurationFilesProcessorImpl.kt | 121 ++------------ .../intellij/openapi/vcs/VcsVFSListener.java | 20 ++- 5 files changed, 187 insertions(+), 112 deletions(-) rename platform/vcs-api/src/com/intellij/openapi/vcs/{ProjectConfigurationFilesProcessor.java => FilesProcessor.java} (79%) create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index e25092e8a54b..1b68c7ab7b84 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -39,8 +39,6 @@ serviceImplementation="com.intellij.openapi.vcs.changes.IgnoredFileGeneratorImpl"/> - diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java b/platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java similarity index 79% rename from platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java rename to platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java index 4ab2bb25abd2..a48cc89e83ab 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessor.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/FilesProcessor.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -public interface ProjectConfigurationFilesProcessor { +public interface FilesProcessor { @NotNull - List processFiles(@NotNull List files, @NotNull VcsVFSListener listener); + List processFiles(@NotNull List files); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt new file mode 100644 index 000000000000..df438cdd977c --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt @@ -0,0 +1,152 @@ +// Copyright 2000-2019 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.openapi.vcs + +import com.intellij.CommonBundle +import com.intellij.ide.util.PropertiesComponent +import com.intellij.notification.Notification +import com.intellij.notification.NotificationAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog +import com.intellij.openapi.vfs.VirtualFile + +abstract class FilesProcessorWithNotificationImpl(protected val project: Project) : FilesProcessor { + + private val vcsNotifier = VcsNotifier.getInstance(project) + + private val projectProperties = PropertiesComponent.getInstance(project) + + private val files = mutableSetOf() + + private val NOTIFICATION_LOCK = Object() + + private var notification: Notification? = null + + abstract val askedBeforeProperty: String + + abstract val doForCurrentProjectProperty: String + + abstract val showActionText: String + abstract val forCurrentProjectActionText: String + abstract val forAllProjectsActionText: String? + abstract val muteActionText: String + + abstract fun notificationTitle(): String + abstract fun notificationMessage(): String + + abstract fun doActionOnChosenFiles(files: Collection) + + abstract fun doFilterFiles(files: Collection): Collection + + abstract fun rememberForAllProjects() + + override fun processFiles(files: List): List { + + val filteredFiles = doFilterFiles(files) + + if (filteredFiles.isEmpty()) return files + + addNewFiles(filteredFiles) + + if (needDoForCurrentProject()) { + doActionOnChosenFiles(acquireValidFiles()) + } + else { + proposeToProcessFiles() + } + + return files - filteredFiles + } + + private fun proposeToProcessFiles() { + synchronized(NOTIFICATION_LOCK) { + if (notAskedBefore() && notificationNotPresent()) { + val notificationActions = mutableListOf(showAction(), addForCurrentProjectAction()).apply { + if (forAllProjectsActionText != null) { + add(forAllProjectsAction()) + } + add(muteAction()) + } + notification = vcsNotifier.notifyMinorInfo(notificationTitle(), notificationMessage(), *notificationActions.toTypedArray()) + } + } + } + + @Synchronized + private fun removeFiles(filesToRemove: Collection) { + files.removeAll(filesToRemove) + } + + @Synchronized + private fun isFilesEmpty() = files.isEmpty() + + @Synchronized + private fun addNewFiles(filesToAdd: Collection) { + files.addAll(filesToAdd) + } + + @Synchronized + private fun acquireValidFiles(): List { + files.removeAll { !it.isValid } + return files.toList() + } + + @Synchronized + private fun clearFiles() { + files.clear() + } + + private fun showAction() = NotificationAction.createSimple(showActionText) { + val allFiles = acquireValidFiles() + if (allFiles.isNotEmpty()) { + with(SelectFilesDialog.init(project, allFiles, null, null, true, true, + CommonBundle.getAddButtonText(), CommonBundle.getCancelButtonText())) { + selectedFiles = allFiles + if (showAndGet()) { + val userSelectedFiles = selectedFiles + doActionOnChosenFiles(userSelectedFiles) + removeFiles(userSelectedFiles) + if (isFilesEmpty()) { + expireNotification() + } + } + } + } + } + + private fun addForCurrentProjectAction() = NotificationAction.create(forCurrentProjectActionText) { _, _ -> + doActionOnChosenFiles(acquireValidFiles()) + projectProperties.setValue(doForCurrentProjectProperty, true) + projectProperties.setValue(askedBeforeProperty, true) + expireNotification() + clearFiles() + } + + private fun forAllProjectsAction() = NotificationAction.create(forAllProjectsActionText!!) { _, _ -> + doActionOnChosenFiles(acquireValidFiles()) + projectProperties.setValue(doForCurrentProjectProperty, true) + projectProperties.setValue(askedBeforeProperty, true) + rememberForAllProjects() + expireNotification() + clearFiles() + } + + private fun muteAction() = NotificationAction.create(muteActionText) { _, notification -> + projectProperties.setValue(doForCurrentProjectProperty, false) + projectProperties.setValue(askedBeforeProperty, true) + notification.expire() + } + + private fun notificationNotPresent() = + synchronized(NOTIFICATION_LOCK) { + notification?.isExpired ?: true + } + + private fun expireNotification() = + synchronized(NOTIFICATION_LOCK) { + notification?.expire() + } + + private fun notAskedBefore() = !projectProperties.getBoolean(askedBeforeProperty, false) + + private fun needDoForCurrentProject() = projectProperties.getBoolean(doForCurrentProjectProperty, false) +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt index 18a51ec5971c..3fd0ec211201 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt @@ -1,15 +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.openapi.vcs -import com.intellij.CommonBundle import com.intellij.ide.highlighter.ModuleFileType import com.intellij.ide.highlighter.ProjectFileType -import com.intellij.ide.util.PropertiesComponent -import com.intellij.notification.Notification -import com.intellij.notification.NotificationAction import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project -import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile @@ -26,17 +21,12 @@ private val configurationFilesExtensionsOutsideStoreDirectory = ContainerUtil.ne private const val SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "SHARE_PROJECT_CONFIGURATION_FILES" private const val ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "ASKED_SHARE_PROJECT_CONFIGURATION_FILES" -class ProjectConfigurationFilesProcessorImpl(private val project: Project, - private val vcsNotifier: VcsNotifier, - private val propertiesComponent: PropertiesComponent) : ProjectConfigurationFilesProcessor { +class ProjectConfigurationFilesProcessorImpl(project: Project, + private val vcsName: String, + private val addChosenFiles: (Collection) -> Unit) + : FilesProcessorWithNotificationImpl(project), FilesProcessor { - private val files = mutableSetOf() - - private val NOTIFICATION_LOCK = Object() - - private var notification: Notification? = null - - override fun processFiles(files: List, listener: VcsVFSListener): List { + override fun doFilterFiles(files: Collection): Collection { val projectBasePath = project.basePath ?: return files val projectBaseDir = LocalFileSystem.getInstance().findFileByPath(projectBasePath) ?: return files val storeDir = getProjectStoreDirectory(projectBaseDir) @@ -45,108 +35,31 @@ class ProjectConfigurationFilesProcessorImpl(private val project: Project, return files } - val projectConfigurationFiles = files.filter { + return files.filter { configurationFilesExtensionsOutsideStoreDirectory.contains(it.extension) || isProjectConfigurationFile(storeDir, it) } - - if (projectConfigurationFiles.isEmpty()) return files - - addNewFiles(projectConfigurationFiles) - - if (needShareFiles()) { - listener.performAdding(acquireValidFiles(), emptyMap()) - } - else { - proposeAddFilesToVcs(listener) - } - - return files - projectConfigurationFiles } - private fun proposeAddFilesToVcs(listener: VcsVFSListener) { - synchronized(NOTIFICATION_LOCK) { - if (notAskedToShareFiles() && notificationNotPresent()) { - notification = vcsNotifier.notifyMinorInfo("", - VcsBundle.message("project.configuration.files.add.notification.message", - listener.myVcs.displayName), - showAction(listener), addAction(listener), muteAction()) - } - } + override fun doActionOnChosenFiles(files: Collection) { + addChosenFiles(files) } - private fun showAction(listener: VcsVFSListener) = NotificationAction.createSimple( - VcsBundle.getString("project.configuration.files.add.notification.action.view")) { - val allProjectFiles = acquireValidFiles() - if (allProjectFiles.isNotEmpty()) { - with(SelectFilesDialog.init(project, allProjectFiles, null, null, true, true, - CommonBundle.getAddButtonText(), CommonBundle.getCancelButtonText())) { - selectedFiles = allProjectFiles - if (showAndGet()) { - val userSelectedFiles = selectedFiles - listener.performAdding(userSelectedFiles, emptyMap()) - removeFiles(userSelectedFiles) - if(isFilesEmpty()){ - expireNotification() - } - } - } - } - } + override val askedBeforeProperty = ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY - @Synchronized - private fun removeFiles(projectConfigurationFiles: Collection) { - files.removeAll(projectConfigurationFiles) - } + override val doForCurrentProjectProperty = SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY - @Synchronized - private fun isFilesEmpty() = files.isEmpty() + override fun notificationTitle() = "" - @Synchronized - private fun addNewFiles(projectConfigurationFiles: Collection) { - files.addAll(projectConfigurationFiles) - } + override fun notificationMessage(): String = VcsBundle.message("project.configuration.files.add.notification.message", vcsName) + override val showActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.view") - @Synchronized - private fun acquireValidFiles(): List { - files.removeAll { !it.isValid } - return files.toList() - } - @Synchronized - private fun clearFiles() { - files.clear() - } + override val forCurrentProjectActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.add") + override val forAllProjectsActionText: String? = null + override val muteActionText: String = VcsBundle.getString("project.configuration.files.add.notification.action.mute") - private fun addAction(listener: VcsVFSListener) = NotificationAction.create( - VcsBundle.getString("project.configuration.files.add.notification.action.add")) { _, _ -> - listener.performAdding(acquireValidFiles(), emptyMap()) - propertiesComponent.setValue(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - propertiesComponent.setValue(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - expireNotification() - clearFiles() - } - - private fun muteAction() = NotificationAction.create( - VcsBundle.getString("project.configuration.files.add.notification.action.mute")) { _, notification -> - propertiesComponent.setValue(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) - propertiesComponent.setValue(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, true) - notification.expire() - } - - private fun notificationNotPresent() = - synchronized(NOTIFICATION_LOCK) { - notification?.isExpired ?: true - } - - private fun expireNotification() = - synchronized(NOTIFICATION_LOCK) { - notification?.expire() - } + override fun rememberForAllProjects() {} private fun isProjectConfigurationFile(storeDir: VirtualFile?, file: VirtualFile) = storeDir != null && VfsUtilCore.isAncestor(storeDir, file, true) - - private fun notAskedToShareFiles() = !propertiesComponent.getBoolean(ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) - - private fun needShareFiles() = propertiesComponent.getBoolean(SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY, false) } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java index 790507de5101..681a7cead3a5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -5,7 +5,6 @@ package com.intellij.openapi.vcs; import com.intellij.openapi.Disposable; import com.intellij.openapi.command.CommandEvent; import com.intellij.openapi.command.CommandListener; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; @@ -19,12 +18,15 @@ import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcsUtil.VcsUtil; +import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.*; +import static java.util.Collections.emptyMap; + public abstract class VcsVFSListener implements Disposable { protected static final Logger LOG = Logger.getInstance(VcsVFSListener.class); @@ -62,7 +64,7 @@ public abstract class VcsVFSListener implements Disposable { protected final List myDeletedFiles = new ArrayList<>(); protected final List myDeletedWithoutConfirmFiles = new ArrayList<>(); protected final List myMovedFiles = new ArrayList<>(); - private final ProjectConfigurationFilesProcessor myProjectConfigurationFilesProcessor; + private final FilesProcessor myProjectConfigurationFilesProcessor; protected enum VcsDeleteType {SILENT, CONFIRM, IGNORE} @@ -79,7 +81,7 @@ public abstract class VcsVFSListener implements Disposable { project.getMessageBus().connect(this).subscribe(CommandListener.TOPIC, new MyCommandAdapter()); myVcsFileListenerContextHelper = VcsFileListenerContextHelper.getInstance(myProject); - myProjectConfigurationFilesProcessor = ServiceManager.getService(myProject, ProjectConfigurationFilesProcessor.class); + myProjectConfigurationFilesProcessor = createProjectConfigurationFilesProcessor(); } @Override @@ -137,7 +139,7 @@ public abstract class VcsVFSListener implements Disposable { LOG.debug("executeAdd. add-option: ", myAddOption.getValue(), ", files to add: ", addedFiles); if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) return; - addedFiles = myProjectConfigurationFilesProcessor.processFiles(addedFiles, this); + addedFiles = myProjectConfigurationFilesProcessor.processFiles(addedFiles); if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) { performAdding(addedFiles, copyFromMap); @@ -316,6 +318,16 @@ public abstract class VcsVFSListener implements Disposable { protected abstract boolean isDirectoryVersioningSupported(); + @SuppressWarnings("unchecked") + private FilesProcessor createProjectConfigurationFilesProcessor() { + return new ProjectConfigurationFilesProcessorImpl(myProject, + myVcs.getDisplayName(), + (files) -> { + performAdding((Collection)files, emptyMap()); + return Unit.INSTANCE; + }); + } + private class MyVirtualFileListener implements VirtualFileListener { @Override public void fileCreated(@NotNull final VirtualFileEvent event) { From 5754aabc829d33d76e54a9071acd695f0d0cb500 Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Fri, 1 Feb 2019 19:55:20 +0300 Subject: [PATCH 084/138] hg: enable process directories in performAdding --- .../hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index dc6622a53445..e383cc7d3d97 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -151,10 +151,6 @@ public class HgVFSListener extends VcsVFSListener { // separate adds from copies for (VirtualFile file : addedFiles) { - if (file.isDirectory()) { - continue; - } - final VirtualFile copyFrom = copyFromMap.get(file); if (copyFrom != null) { copies.put(copyFrom, file); @@ -176,7 +172,12 @@ public class HgVFSListener extends VcsVFSListener { } for (VirtualFile file : addedFiles) { - dirtyScopeManager.fileDirty(file); + if (file.isDirectory()) { + dirtyScopeManager.dirDirtyRecursively(file); + } + else { + dirtyScopeManager.fileDirty(file); + } } } }).queue(); From 7bbc30215b91a647511214ee4daf90a8d65c50fd Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Tue, 27 Nov 2018 19:58:16 +0300 Subject: [PATCH 085/138] vcs: prompt add externally added files to VCS (IDEA-52058) --- .../src/messages/VcsBundle.properties | 4 ++ .../vcs/ExternallyAddedFilesProcessorImpl.kt | 34 +++++++++++ .../intellij/openapi/vcs/VcsVFSListener.java | 55 +++++++++++++++++- .../intellij/openapi/vcs/TestVcsNotifier.java | 5 ++ .../src/git4idea/vfs/GitVFSListener.java | 10 +++- .../GitExternalFileNotifierTest.kt | 56 +++++++++++++++++++ .../src/org/zmlx/hg4idea/HgVFSListener.java | 10 +++- 7 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt create mode 100644 plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index a7949548f095..905fcad7a049 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -609,3 +609,7 @@ project.configuration.files.add.notification.action.view=View Files project.configuration.files.add.notification.action.add=Always Add project.configuration.files.add.notification.action.mute=Don't Ask Again +external.files.add.notification.message=Externally added files can be added to {0} +external.files.add.notification.action.view=View Files +external.files.add.notification.action.add=Always Add +external.files.add.notification.action.mute=Don't Ask Again \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt new file mode 100644 index 000000000000..b393126fdd01 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ExternallyAddedFilesProcessorImpl.kt @@ -0,0 +1,34 @@ +// Copyright 2000-2019 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.openapi.vcs + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile + +private const val ADD_EXTERNAL_FILES_PROPERTY = "ADD_EXTERNAL_FILES" +private const val ASKED_ADD_EXTERNAL_FILES_PROPERTY = "ASKED_ADD_EXTERNAL_FILES" + +class ExternallyAddedFilesProcessorImpl(project: Project, + private val vcsName: String, + private val addChosenFiles: (Collection) -> Unit) + : FilesProcessorWithNotificationImpl(project), FilesProcessor { + + override val askedBeforeProperty = ASKED_ADD_EXTERNAL_FILES_PROPERTY + override val doForCurrentProjectProperty = ADD_EXTERNAL_FILES_PROPERTY + + override val showActionText: String = VcsBundle.message("external.files.add.notification.action.view") + override val forCurrentProjectActionText: String = VcsBundle.message("external.files.add.notification.action.add") + override val forAllProjectsActionText: String? = null + override val muteActionText: String = VcsBundle.message("external.files.add.notification.action.mute") + + override fun notificationTitle() = "" + + override fun notificationMessage(): String = VcsBundle.message("external.files.add.notification.message", vcsName) + + override fun doActionOnChosenFiles(files: Collection) { + addChosenFiles(files) + } + + override fun doFilterFiles(files: Collection) = files + + override fun rememberForAllProjects() {} +} \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java index 681a7cead3a5..5110254285d2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsVFSListener.java @@ -65,6 +65,7 @@ public abstract class VcsVFSListener implements Disposable { protected final List myDeletedWithoutConfirmFiles = new ArrayList<>(); protected final List myMovedFiles = new ArrayList<>(); private final FilesProcessor myProjectConfigurationFilesProcessor; + private final FilesProcessor myExternalFilesProcessor; protected enum VcsDeleteType {SILENT, CONFIRM, IGNORE} @@ -82,6 +83,7 @@ public abstract class VcsVFSListener implements Disposable { myVcsFileListenerContextHelper = VcsFileListenerContextHelper.getInstance(myProject); myProjectConfigurationFilesProcessor = createProjectConfigurationFilesProcessor(); + myExternalFilesProcessor = createExternalFilesProcessor(); } @Override @@ -93,6 +95,10 @@ public abstract class VcsVFSListener implements Disposable { return !isUnderMyVcs(event.getFile()); } + private static boolean isExternalEvent(@NotNull VirtualFileEvent event) { + return event.isFromRefresh(); + } + private boolean isUnderMyVcs(@NotNull VirtualFile file) { return myVcsManager.getVcsFor(file) == myVcs && myVcsManager.isFileInContent(file) && @@ -156,6 +162,17 @@ public abstract class VcsVFSListener implements Disposable { } } + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { + executeAddCallback.executeAdd(addedFiles, copyFromMap); + } + + @FunctionalInterface + protected interface ExecuteAddCallback { + void executeAdd(@NotNull List addedFiles, @NotNull Map copyFromMap); + } + protected void saveUnsavedVcsIgnoreFiles() { FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); Set ignoreFileNames = VcsUtil.getVcsIgnoreFileNames(myProject); @@ -229,10 +246,20 @@ public abstract class VcsVFSListener implements Disposable { } protected void fileAdded(@NotNull VirtualFileEvent event, @NotNull VirtualFile file) { - if (!isEventIgnored(event) && !myChangeListManager.isIgnoredFile(file) && + if (isExternalEvent(event) + && !myChangeListManager.isIgnoredFile(file) && VcsUtil.getVcsRootFor(myProject, file) != null) { + LOG.debug("Adding external file [", file, "]"); + if (file.isDirectory()) { + processExternalCreatedFiles(ContainerUtil.newArrayList(file)); + } else { + executeAddWithoutIgnores(ContainerUtil.newArrayList(file), Collections.emptyMap(), + (notIgnoredFiles, copiedFilesMap) -> processExternalCreatedFiles(notIgnoredFiles)); + } + } + else if (!isEventIgnored(event) && (isDirectoryVersioningSupported() || !file.isDirectory())) { LOG.debug("Adding [", file, "] to added files"); - myAddedFiles.add(event.getFile()); + myAddedFiles.add(file); } } @@ -318,6 +345,16 @@ public abstract class VcsVFSListener implements Disposable { protected abstract boolean isDirectoryVersioningSupported(); + @SuppressWarnings("unchecked") + private FilesProcessor createExternalFilesProcessor() { + return new ExternallyAddedFilesProcessorImpl(myProject, + myVcs.getDisplayName(), + (files) -> { + performAdding((Collection)files, emptyMap()); + return Unit.INSTANCE; + }); + } + @SuppressWarnings("unchecked") private FilesProcessor createProjectConfigurationFilesProcessor() { return new ProjectConfigurationFilesProcessorImpl(myProject, @@ -425,6 +462,20 @@ public abstract class VcsVFSListener implements Disposable { } } + private void processExternalCreatedFiles(@NotNull List files) { + if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) return; + + files = myProjectConfigurationFilesProcessor.processFiles(files); + if (files.isEmpty()) return; + + if (myAddOption.getValue() == VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) { + performAdding(files, Collections.emptyMap()); + } + else { + myExternalFilesProcessor.processFiles(files); + } + } + private class MyCommandAdapter implements CommandListener { private int myCommandLevel; diff --git a/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java b/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java index 2f16552ef0d3..a2f51131b051 100644 --- a/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java +++ b/platform/vcs-tests/src/com/intellij/openapi/vcs/TestVcsNotifier.java @@ -41,6 +41,11 @@ public class TestVcsNotifier extends VcsNotifier { return notification; } + @NotNull + public List getNotifications(){ + return ContainerUtil.unmodifiableOrEmptyList(myNotifications); + } + public void cleanup() { myNotifications.clear(); } diff --git a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java index 47e692476f87..a9f91201fcb2 100644 --- a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java +++ b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java @@ -90,6 +90,14 @@ public class GitVFSListener extends VcsVFSListener { @Override protected void executeAdd(@NotNull final List addedFiles, @NotNull final Map copiedFiles) { + executeAddWithoutIgnores(addedFiles, copiedFiles, + (notIgnoredAddedFiles, copiedFilesMap) -> originalExecuteAdd(notIgnoredAddedFiles, copiedFilesMap)); + } + + @Override + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { saveUnsavedVcsIgnoreFiles(); // Filter added files before further processing Map> sortedFiles; @@ -117,7 +125,7 @@ public class GitVFSListener extends VcsVFSListener { } addedFiles.retainAll(retainedFiles); - AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> originalExecuteAdd(addedFiles, copiedFiles)); + AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> executeAddCallback.executeAdd(addedFiles, copyFromMap)); } }); } diff --git a/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt b/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt new file mode 100644 index 000000000000..c8422343e8ae --- /dev/null +++ b/plugins/git4idea/tests/git4idea/notification/GitExternalFileNotifierTest.kt @@ -0,0 +1,56 @@ +// 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 git4idea.notification + +import com.intellij.openapi.vcs.VcsBundle +import com.intellij.openapi.vcs.VcsConfiguration +import com.intellij.openapi.vcs.VcsShowConfirmationOption +import com.intellij.testFramework.RunAll +import com.intellij.testFramework.vcs.AbstractVcsTestCase.setStandardConfirmation +import com.intellij.util.ThrowableRunnable +import git4idea.test.GitSingleRepoTest +import junit.framework.TestCase + +class GitExternalFileNotifierTest : GitSingleRepoTest() { + + override fun setUp() { + super.setUp() + + setStandardConfirmation(project, vcs.name, VcsConfiguration.StandardConfirmation.ADD, VcsShowConfirmationOption.Value.SHOW_CONFIRMATION) + projectRoot.children //ensure that all subsequent VFS events will be fired after new files added to projectRoot + } + + override fun tearDown() { + RunAll() + .append(ThrowableRunnable { + setStandardConfirmation(project, vcs.name, VcsConfiguration.StandardConfirmation.ADD, + VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY) + }) + .append(ThrowableRunnable { super.tearDown() }) + .run() + } + + fun `test notification after external files added`(){ + file("file1.txt").create() + file("file2.txt").create() + + refresh() + + assertNotificationByMessage(VcsBundle.message("external.files.add.notification.message", vcs.displayName)) + } + + fun `test notification after external files and project configuration files added`(){ + file("file1.txt").create() + file("file2.txt").create() + file("module.iml").create() + + refresh() + + assertSize(2, vcsNotifier.notifications) + assertNotificationByMessage(VcsBundle.message("external.files.add.notification.message", vcs.displayName)) + assertNotificationByMessage(VcsBundle.message("project.configuration.files.add.notification.message", vcs.displayName)) + } + + private fun assertNotificationByMessage(notificationContent: String) = + vcsNotifier.notifications.find { it.content == notificationContent } + ?: TestCase.fail("Notification $notificationContent not found") +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java index e383cc7d3d97..2ee65e67b0bd 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgVFSListener.java @@ -67,6 +67,14 @@ public class HgVFSListener extends VcsVFSListener { @Override protected void executeAdd(@NotNull final List addedFiles, @NotNull final Map copyFromMap) { + executeAddWithoutIgnores(addedFiles, copyFromMap, + (notIgnoredAddedFiles, copiedFilesMap) -> originalExecuteAdd(notIgnoredAddedFiles, copiedFilesMap)); + } + + @Override + protected void executeAddWithoutIgnores(@NotNull List addedFiles, + @NotNull Map copyFromMap, + @NotNull ExecuteAddCallback executeAddCallback) { saveUnsavedVcsIgnoreFiles(); // if a file is copied from another repository, then 'hg add' should be used instead of 'hg copy'. // Thus here we remove such files from the copyFromMap. @@ -104,7 +112,7 @@ public class HgVFSListener extends VcsVFSListener { // select files to add if there is something to select if (!addedFiles.isEmpty() || !copyFromMap.isEmpty()) { - AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> originalExecuteAdd(addedFiles, copyFromMap)); + AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> executeAddCallback.executeAdd(addedFiles, copyFromMap)); } } }.queue(); From 31b3538432c498ec7a074ebb276190385fd1565d Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Thu, 29 Nov 2018 16:07:43 +0300 Subject: [PATCH 086/138] vcs: persist list of files in ProjectConfigurationFilesProcessor (IDEA-203012) --- .../src/META-INF/VcsExtensions.xml | 4 +- .../ProjectConfigurationFilesProcessorImpl.kt | 53 ++++++++++++++++--- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index 1b68c7ab7b84..7a2635fa4c67 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -38,7 +38,9 @@ + serviceImplementation="com.intellij.openapi.vcs.changes.IgnoredFileGeneratorImpl$IgnoredFileRootStore"/> + diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt index 3fd0ec211201..98f93bd8aabc 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ProjectConfigurationFilesProcessorImpl.kt @@ -3,6 +3,7 @@ package com.intellij.openapi.vcs import com.intellij.ide.highlighter.ModuleFileType import com.intellij.ide.highlighter.ProjectFileType +import com.intellij.openapi.components.* import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem @@ -14,9 +15,8 @@ import com.intellij.util.containers.ContainerUtil private val LOG = Logger.getInstance(ProjectConfigurationFilesProcessorImpl::class.java) -private val configurationFilesExtensionsOutsideStoreDirectory = ContainerUtil.newHashSet( - ProjectFileType.DEFAULT_EXTENSION, - ModuleFileType.DEFAULT_EXTENSION) +private val configurationFilesExtensionsOutsideStoreDirectory = + ContainerUtil.newHashSet(ProjectFileType.DEFAULT_EXTENSION, ModuleFileType.DEFAULT_EXTENSION) private const val SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "SHARE_PROJECT_CONFIGURATION_FILES" private const val ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY = "ASKED_SHARE_PROJECT_CONFIGURATION_FILES" @@ -26,22 +26,32 @@ class ProjectConfigurationFilesProcessorImpl(project: Project, private val addChosenFiles: (Collection) -> Unit) : FilesProcessorWithNotificationImpl(project), FilesProcessor { + private val fileSystem = LocalFileSystem.getInstance() + + private val projectConfigurationFilesStore = getProjectConfigurationFilesStore(project) + override fun doFilterFiles(files: Collection): Collection { val projectBasePath = project.basePath ?: return files - val projectBaseDir = LocalFileSystem.getInstance().findFileByPath(projectBasePath) ?: return files + val projectBaseDir = fileSystem.findFileByPath(projectBasePath) ?: return files val storeDir = getProjectStoreDirectory(projectBaseDir) if (project.isDirectoryBased && storeDir == null) { LOG.warn("Cannot find store directory for project in directory ${projectBaseDir.path}") return files } - return files.filter { + val filteredFiles = files.filter { configurationFilesExtensionsOutsideStoreDirectory.contains(it.extension) || isProjectConfigurationFile(storeDir, it) } + + val previouslyStoredFiles = projectConfigurationFilesStore.cleanupAndGetValidFiles() + projectConfigurationFilesStore.addAll(filteredFiles) + + return filteredFiles + previouslyStoredFiles } override fun doActionOnChosenFiles(files: Collection) { addChosenFiles(files) + projectConfigurationFilesStore.removeAll(files) } override val askedBeforeProperty = ASKED_SHARE_PROJECT_CONFIGURATION_FILES_PROPERTY @@ -62,4 +72,35 @@ class ProjectConfigurationFilesProcessorImpl(project: Project, private fun isProjectConfigurationFile(storeDir: VirtualFile?, file: VirtualFile) = storeDir != null && VfsUtilCore.isAncestor(storeDir, file, true) -} \ No newline at end of file +} + +@State(name = "ProjectConfigurationFiles", storages = [Storage(StoragePathMacros.WORKSPACE_FILE)]) +class ProjectConfigurationFilesStoreState : PersistentStateComponent { + + private val fileSystem = LocalFileSystem.getInstance() + + data class State(var files: MutableList = mutableListOf()) + + var myState = State() + + fun cleanupAndGetValidFiles(): List { + val validFiles = state.files.mapNotNull { fileSystem.findFileByPath(it)} + state.files.retainAll(validFiles.map { it.path }) + return validFiles + } + + fun addAll(files: Collection) = + state.files.addAll(files.map(VirtualFile::getPath)) + + fun removeAll(files: Collection) = + state.files.removeAll(files.map(VirtualFile::getPath)) + + override fun getState() = myState + + override fun loadState(state: State) { + myState = state + } +} + +fun getProjectConfigurationFilesStore(project: Project): ProjectConfigurationFilesStoreState = + ServiceManager.getService(project, ProjectConfigurationFilesStoreState::class.java) From 2dc7536f43f35e75b8d8788924fcf0cdb56528a8 Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Fri, 28 Dec 2018 14:42:51 +0300 Subject: [PATCH 087/138] vcs: make notification in files processor sticky --- .../openapi/vcs/FilesProcessorWithNotificationImpl.kt | 2 +- .../vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt index df438cdd977c..ca3fc1fd0157 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/FilesProcessorWithNotificationImpl.kt @@ -66,7 +66,7 @@ abstract class FilesProcessorWithNotificationImpl(protected val project: Project } add(muteAction()) } - notification = vcsNotifier.notifyMinorInfo(notificationTitle(), notificationMessage(), *notificationActions.toTypedArray()) + notification = vcsNotifier.notifyMinorInfo(true, notificationTitle(), notificationMessage(), *notificationActions.toTypedArray()) } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java index 68bb4c80cb42..4f9c6dec661e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/VcsNotifier.java @@ -180,6 +180,11 @@ public class VcsNotifier { return notify(STANDARD_NOTIFICATION, title, message, NotificationType.INFORMATION, actions); } + @NotNull + public Notification notifyMinorInfo(boolean sticky, @NotNull String title, @NotNull String message, NotificationAction... actions) { + return notify(sticky ? IMPORTANT_ERROR_NOTIFICATION : STANDARD_NOTIFICATION, title, message, NotificationType.INFORMATION, actions); + } + public Notification logInfo(@NotNull String title, @NotNull String message) { return notify(SILENT_NOTIFICATION, title, message, NotificationType.INFORMATION); } From 564ceecb4ec861faf9eb321aec1a9e53783eaef0 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Feb 2019 21:05:52 +0300 Subject: [PATCH 088/138] EA-135323: add logging to find a module type that does not provide an icon --- .../com/intellij/ide/scopeView/ScopeViewTreeModel.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java index e07bc6b99c2d..3f92245e92e6 100644 --- a/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java +++ b/platform/lang-impl/src/com/intellij/ide/scopeView/ScopeViewTreeModel.java @@ -1008,7 +1008,13 @@ public final class ScopeViewTreeModel extends BaseTreeModel im if (!groups.isEmpty() || roots.isEmpty()) return AllIcons.Nodes.ModuleGroup; Object id = roots.get(0).node.getRootID(); if (roots.stream().anyMatch(root -> !root.node.getRootID().equals(id))) return AllIcons.Nodes.ModuleGroup; - return id instanceof Module ? ModuleType.get((Module)id).getIcon() : AllIcons.Nodes.Module; + if (id instanceof Module) { + ModuleType type = ModuleType.get((Module)id); + Icon icon = type.getIcon(); + if (icon != null) return icon; + LOG.warn(type.getName() + " type have no icon for " + id); + } + return AllIcons.Nodes.Module; } @Nullable From 2a6249046bd292b3aefd4f3dbd08a4c60142affe Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 01:40:43 +0300 Subject: [PATCH 089/138] diff: cleanup - remove yellow code --- .../diff/comparison/MergeResolveUtil.kt | 2 +- .../com/intellij/diff/comparison/TrimUtil.kt | 8 ++++---- .../intellij/diff/impl/DiffSettingsHolder.kt | 4 ++-- .../settings/DiffSettingsConfigurable.java | 1 - .../ExternalDiffSettingsConfigurable.java | 1 - .../diff/tools/binary/BinaryDiffTool.java | 1 - .../UnifiedEditorRangeHighlighter.java | 1 - .../diff/tools/util/FoldingModelSupport.java | 2 +- .../diff/tools/util/ThreeDiffSplitter.java | 2 +- .../tools/util/base/TextDiffSettingsHolder.kt | 4 ++-- .../openapi/diff/impl/DiffPanelImpl.java | 1 + .../diff/impl/dir/actions/DirDiffAction.java | 2 -- .../diff/comparison/ComparisonUtilTest.kt | 3 +-- .../diff/comparison/ComparisonUtilTestBase.kt | 4 ++-- .../diff/comparison/LineComparisonUtilTest.kt | 16 ++++++++-------- .../diff/contents/FragmentContentTest.kt | 18 +++++++++--------- .../com/intellij/diff/merge/MergeAutoTest.kt | 12 ++++++------ .../com/intellij/diff/merge/MergeTestBase.kt | 13 ++++++------- .../fragmented/UnifiedFragmentBuilderTest.kt | 6 +++--- .../com/intellij/diff/util/DiffUtilTest.kt | 1 - 20 files changed, 47 insertions(+), 55 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt index 53d30b6b8cad..742098f49e5e 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/MergeResolveUtil.kt @@ -252,7 +252,7 @@ private class GreedyHelper(val leftText: CharSequence, val baseText: CharSequenc } // we faced conflicting insertions - resolve failed - return null; + return null } return newContent diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt index 6f61a0fb608f..a9e895af8992 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt +++ b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.kt @@ -192,10 +192,10 @@ fun expandWhitespacesBackward(text1: CharSequence, text2: CharSequence, text3: C } -fun trimExpandRange(start1: Int, start2: Int, end1: Int, end2: Int, - equals: (Int, Int) -> Boolean, - ignored1: (Int) -> Boolean, - ignored2: (Int) -> Boolean): Range { +fun trimExpandRange(start1: Int, start2: Int, end1: Int, end2: Int, + equals: (Int, Int) -> Boolean, + ignored1: (Int) -> Boolean, + ignored2: (Int) -> Boolean): Range { return trimExpand(start1, start2, end1, end2, { index1, index2 -> equals(index1, index2) }, { index -> ignored1(index) }, diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt index 8ee18999d439..27147d5caf7b 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt @@ -50,14 +50,14 @@ class DiffSettingsHolder : PersistentStateComponent { fun getSettings(place: String?): DiffSettings { val placeKey = place ?: DiffPlaces.DEFAULT - val placeSettings = myState.PLACES_MAP.getOrPut(placeKey, { defaultPlaceSettings(placeKey) }) + val placeSettings = myState.PLACES_MAP.getOrPut(placeKey) { defaultPlaceSettings(placeKey) } return DiffSettings(myState.SHARED_SETTINGS, placeSettings) } private fun copyStateWithoutDefaults(): State { val result = State() result.SHARED_SETTINGS = myState.SHARED_SETTINGS - result.PLACES_MAP = DiffUtil.trimDefaultValues(myState.PLACES_MAP, { defaultPlaceSettings(it) }) + result.PLACES_MAP = DiffUtil.trimDefaultValues(myState.PLACES_MAP) { defaultPlaceSettings(it) } return result } diff --git a/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java b/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java index 280248344a22..ce1075282c8e 100644 --- a/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java +++ b/platform/diff-impl/src/com/intellij/diff/settings/DiffSettingsConfigurable.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.settings; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java b/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java index 225275bfe589..7f317b653eca 100644 --- a/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java +++ b/platform/diff-impl/src/com/intellij/diff/settings/ExternalDiffSettingsConfigurable.java @@ -15,7 +15,6 @@ */ package com.intellij.diff.settings; -import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java index 8093f89a30f9..33d0a0e55bb0 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/binary/BinaryDiffTool.java @@ -17,7 +17,6 @@ package com.intellij.diff.tools.binary; import com.intellij.diff.DiffContext; import com.intellij.diff.FrameDiffTool; -import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.DiffRequest; import org.jetbrains.annotations.NotNull; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java index d4f577d4e2f2..fab1673016e3 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedEditorRangeHighlighter.java @@ -16,7 +16,6 @@ package com.intellij.diff.tools.fragmented; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java index ba7aba65dfa0..57378982faad 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java @@ -320,7 +320,7 @@ public class FoldingModelSupport { private class MyFoldingListener implements FoldingListener { private final int myIndex; - @NotNull Set myModifiedRegions = new HashSet<>(); + @NotNull private final Set myModifiedRegions = new HashSet<>(); MyFoldingListener(int index) { myIndex = index; diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java b/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java index 47bca5da5f15..fb2922df74d4 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/ThreeDiffSplitter.java @@ -160,7 +160,7 @@ public class ThreeDiffSplitter extends JPanel { Divider(@NotNull Side side) { mySide = side; - enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt index 4c9990156d0e..51b43f73158f 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt @@ -144,14 +144,14 @@ class TextDiffSettingsHolder : PersistentStateComponent Unit): Unit = doTest(TestType.CHAR_SMART, f) internal fun splitter(squash: Boolean = false, trim: Boolean = false, f: TestBuilder.() -> Unit) { - doTest(TestType.SPLITTER, { + doTest(TestType.SPLITTER) { postprocess(squash, trim) f() - }) + } } private fun doTest(type: TestType, f: TestBuilder.() -> Unit) { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt index 95f6261c15dc..6f46cf110a89 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/LineComparisonUtilTest.kt @@ -323,13 +323,13 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test prefer smaller amount of chunks`() { - lines() { + lines { ("X_A_X_Y_" - "X_Y_") ("-_-_ _ _" - " _ _").default() testAll() } - lines() { + lines { (" __x___y" - "__y") ("-**-*__ " - "__ ").default() default(del(0, 0, 3)) @@ -387,7 +387,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testAll() } - splitter() { + splitter { ("M===_X===_Y===" - " Y===_X===_N") // TODO: default(mod(0, 0, 1, 1), mod(2, 2, 1, 1)) default(mod(0, 0, 1, 1), mod(1, 1, 1, 1), mod(2, 2, 1, 1)) @@ -413,7 +413,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test trim changed blocks after second step correction`() { - lines() { + lines { ("====}_==== }_Y_====}" - "====}_Y_====}") (" _------_ _ " - " _ _ ").default() // result after second step correction (" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count' @@ -430,20 +430,20 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { } fun `test ignore whitespace policy does not applies two-step correction`() { - lines() { + lines { ("1_ _ 1" - " 1") ("-_-_ " - " ").default() (" _-_---" - " ").trim() testAll() } - lines() { + lines { (" 1_ _1" - " 1") (" _-_-" - " ").default() testAll() } - lines() { + lines { ("X_ Y_X" - "Y ") ("-_--_-" - "--").default() ("-_ _-" - " ").trim() @@ -466,7 +466,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() { testAll() } - lines() { + lines { ("X_X __Y" - "X__Z") (" _--__-" - " __-").default() ("-_ __-" - " __-").trim() diff --git a/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt b/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt index 62d155138e0b..52f66af68b2a 100644 --- a/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/contents/FragmentContentTest.kt @@ -83,22 +83,22 @@ class FragmentContentTest : HeavyDiffTestCase() { fun testRemoveOriginalFragment() { assertTrue(fragment.isWritable) - replaceString(document, 2, 8, ""); - assertEquals("0189", document.text); + replaceString(document, 2, 8, "") + assertEquals("0189", document.text) assertEquals("Invalid selection range", fragment.text) assertFalse(fragment.isWritable) } fun testRemoveListeners() { - replaceString(fragment, 0, 1, "x"); - assertEquals("012x456789", document.text); + replaceString(fragment, 0, 1, "x") + assertEquals("012x456789", document.text) fragmentContent.onAssigned(false) - replaceString(fragment, 0, 1, "3"); - assertEquals("012x456789", document.text); - replaceString(document, 3, 4, "y"); - assertEquals("012y456789", document.text); - assertEquals("3456", fragment.text); + replaceString(fragment, 0, 1, "3") + assertEquals("012x456789", document.text) + replaceString(document, 3, 4, "y") + assertEquals("012y456789", document.text) + assertEquals("3456", fragment.text) fragmentContent.onAssigned(true) } diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt index 5f8e8b6d4883..c5dab5c90eb3 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt @@ -57,7 +57,7 @@ class MergeAutoTest : MergeTestBase() { } } - private fun TestBuilder.doApply(): Unit { + private fun TestBuilder.doApply() { val index = RNG.nextInt(changes.size) val change = changes[index] @@ -67,7 +67,7 @@ class MergeAutoTest : MergeTestBase() { command(change) { viewer.replaceChange(change, side, modifier) } } - private fun TestBuilder.doIgnore(): Unit { + private fun TestBuilder.doIgnore() { val index = RNG.nextInt(changes.size) val change = changes[index] @@ -77,18 +77,18 @@ class MergeAutoTest : MergeTestBase() { command(change) { viewer.ignoreChange(change, side, modifier) } } - private fun TestBuilder.doTryResolve(): Unit { + private fun TestBuilder.doTryResolve() { val index = RNG.nextInt(changes.size) val change = changes[index] command(change) { viewer.resolveChangeAutomatically(change, ThreeSide.BASE) } } - private fun TestBuilder.doModifyText(): Unit { + private fun TestBuilder.doModifyText() { val length = document.textLength - var index1: Int = 0 - var index2: Int = 0 + var index1 = 0 + var index2 = 0 if (length != 0) { index1 = RNG.nextInt(length) index2 = index1 + RNG.nextInt(length - index1) diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt index 5712ca0a6e0b..3ce619a2f21b 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt @@ -111,17 +111,17 @@ abstract class MergeTestBase : HeavyDiffTestCase() { // Modification // - fun command(affected: TextMergeChange, f: () -> Unit): Unit { + fun command(affected: TextMergeChange, f: () -> Unit) { command(listOf(affected), f) } - fun command(affected: List? = null, f: () -> Unit): Unit { + fun command(affected: List? = null, f: () -> Unit) { viewer.executeMergeCommand(null, affected, f) UIUtil.dispatchAllInvocationEvents() } - fun write(f: () -> Unit): Unit { - ApplicationManager.getApplication().runWriteAction({ CommandProcessor.getInstance().executeCommand(project, f, null, null) }) + fun write(f: () -> Unit) { + ApplicationManager.getApplication().runWriteAction { CommandProcessor.getInstance().executeCommand(project, f, null, null) } } fun Int.ignore(side: Side, modifier: Boolean = false) { @@ -334,8 +334,7 @@ abstract class MergeTestBase : HeavyDiffTestCase() { operator fun Int.not(): LineColHelper = LineColHelper(this) operator fun LineColHelper.minus(col: Int): LineCol = LineCol(this.line, col) - inner class LineColHelper(val line: Int) { - } + inner class LineColHelper(val line: Int) inner class LineCol(val line: Int, val col: Int) { fun toOffset(): Int = editor.document.getLineStartOffset(line) + col @@ -384,7 +383,7 @@ abstract class MergeTestBase : HeavyDiffTestCase() { } private fun recordChangeState(viewer: MyThreesideViewer, change: TextMergeChange): ChangeState { - val document = viewer.editor.document; + val document = viewer.editor.document val content = DiffUtil.getLinesContent(document, change.startLine, change.endLine) val resolved = diff --git a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt index 6503c4e82c43..7596b94bce20 100644 --- a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderTest.kt @@ -236,9 +236,9 @@ class UnifiedFragmentBuilderTest : DiffTestCase() { builder.exec() - val lineCount1 = input1.count({ it == '_' }) + 1 - val lineCount2 = input2.count({ it == '_' }) + 1 - val resultLineCount = result.count({ it == '_' }) + 1 + val lineCount1 = input1.count { it == '_' } + 1 + val lineCount2 = input2.count { it == '_' } + 1 + val resultLineCount = result.count { it == '_' } + 1 val lineIterable = DiffIterableUtil.create(fragments.map { Range(it.startLine1, it.endLine1, it.startLine2, it.endLine2) }, lineCount1, lineCount2) diff --git a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt index 82732b3a6367..7f916e5e5d9e 100644 --- a/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/util/DiffUtilTest.kt @@ -38,7 +38,6 @@ import com.intellij.openapi.diff.DiffBundle import com.intellij.openapi.editor.impl.DocumentImpl import com.intellij.util.containers.ContainerUtil import java.io.File -import java.util.* class DiffUtilTest : DiffTestCase() { fun `test getSortedIndexes`() { From 0913c15eea5d69351b16d5b67df27e4eb1d9e9ba Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 01:42:54 +0300 Subject: [PATCH 090/138] merge: do not sync scroll position twice --- .../util/side/ThreesideTextDiffViewer.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java index 5f04ce0ab025..6b634703484c 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/side/ThreesideTextDiffViewer.java @@ -53,8 +53,7 @@ public abstract class ThreesideTextDiffViewer extends ThreesideDiffViewer myEditors; @NotNull private final List myEditableEditors; - @NotNull private final MyVisibleAreaListener myVisibleAreaListener1 = new MyVisibleAreaListener(Side.LEFT); - @NotNull private final MyVisibleAreaListener myVisibleAreaListener2 = new MyVisibleAreaListener(Side.RIGHT); + @NotNull private final MyVisibleAreaListener myVisibleAreaListener = new MyVisibleAreaListener(); @Nullable protected ThreesideSyncScrollSupport mySyncScrollSupport; @NotNull protected final SetEditorSettingsAction myEditorSettingsAction; @@ -127,11 +126,9 @@ public abstract class ThreesideTextDiffViewer extends ThreesideDiffViewer Date: Mon, 4 Feb 2019 21:39:40 +0300 Subject: [PATCH 091/138] IDEA-164838 Open three new same windows when do "Open In New Editor Window" --- .../fileEditor/impl/FileEditorManagerImpl.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index 8621f8faa73f..275ee01e8fa0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -698,6 +698,8 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis private static boolean isOpenInNewWindow() { AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); + // openFile... methods can be called several times in a row with the same InputEvent but we should open just one new window in this case + if (event instanceof InputEvent && ((InputEvent)event).isConsumed()) return false; // Shift was used while clicking if (event instanceof MouseEvent && @@ -705,14 +707,23 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Persis (event.getID() == MouseEvent.MOUSE_CLICKED || event.getID() == MouseEvent.MOUSE_PRESSED || event.getID() == MouseEvent.MOUSE_RELEASED)) { + ((MouseEvent)event).consume(); return true; } if (event instanceof KeyEvent) { KeyEvent ke = (KeyEvent)event; - Keymap keymap = KeymapManager.getInstance().getActiveKeymap(); + KeymapManager keymapManager = KeymapManager.getInstance(); + if (keymapManager == null) { + return false; + } + Keymap keymap = keymapManager.getActiveKeymap(); String[] ids = keymap.getActionIds(KeyStroke.getKeyStroke(ke.getKeyCode(), ke.getModifiers())); - return Arrays.asList(ids).contains("OpenElementInNewWindow"); + boolean inNewWindow = Arrays.asList(ids).contains("OpenElementInNewWindow"); + if (inNewWindow) { + ke.consume(); + } + return inNewWindow; } return false; From 871c961ad4f1ea1fc5d20b4a302e0fb97326795a Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Feb 2019 21:54:49 +0300 Subject: [PATCH 092/138] diff: fix binary compatibility with 'jsondiff' plugin follow-up: 1d3d5ef44051234737d13803854566428e6fc491 --- .../com/intellij/diff/actions/CompareFilesAction.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index ddb6384ae1f1..de4db8f746df 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -74,7 +74,7 @@ public class CompareFilesAction extends BaseShowDiffAction { @Override protected boolean isAvailable(@NotNull AnActionEvent e) { - DiffRequest request = e.getData(DIFF_REQUEST); + DiffRequest request = getDiffRequest(e); if (request != null) { return true; } @@ -95,11 +95,16 @@ public class CompareFilesAction extends BaseShowDiffAction { } } + @Nullable + protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { + return e.getData(DIFF_REQUEST); + } + @Nullable @Override protected DiffRequestChain getDiffRequestChain(@NotNull AnActionEvent e) { Project project = e.getProject(); - DiffRequest diffRequest = e.getData(DIFF_REQUEST); + DiffRequest diffRequest = getDiffRequest(e); if (diffRequest != null) { return new SimpleDiffRequestChain(diffRequest); } From fe3c5e6905f434b81b56e84d84c8431aaac845ea Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 4 Feb 2019 20:03:10 +0100 Subject: [PATCH 093/138] don't wrap PCE --- .../intellij/psi/util/MethodSignatureBackedByPsiMethod.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java index a1acf2b859db..c0137fb89c25 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java +++ b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBackedByPsiMethod.java @@ -16,6 +16,7 @@ package com.intellij.psi.util; import com.intellij.diagnostic.PluginException; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; @@ -81,6 +82,9 @@ public class MethodSignatureBackedByPsiMethod extends MethodSignatureBase { try { substitutor.ensureValid(); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass(e, method.getClass()); } From efa27f082c3faa9880d8a4ba067d11dbb15f1201 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 20:22:16 +0100 Subject: [PATCH 094/138] FUS: make counter collector attribute camelcase --- .../fus/collectors/CounterUsageCollectorEP.java | 12 +++++++++++- .../service/fus/collectors/FUCounterUsageLogger.java | 6 +++++- .../src/META-INF/PlatformExtensions.xml | 10 +++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java index 39aaba88dbb2..a6e6cc816493 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/CounterUsageCollectorEP.java @@ -4,14 +4,24 @@ package com.intellij.internal.statistic.service.fus.collectors; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.util.xmlb.annotations.Attribute; +import org.jetbrains.annotations.Nullable; public class CounterUsageCollectorEP extends AbstractExtensionPointBean { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.statistics.counterUsagesCollector"); - @Attribute("group_id") + @Attribute("groupId") public String groupID; + @Deprecated + @Attribute("group_id") + public String legacyGroupID; + @Attribute("version") public int version; + + @Nullable + public String getGroupId() { + return groupID != null ? groupID : legacyGroupID; + } } diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java index 738ddf252c31..e27dec90342c 100644 --- a/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java +++ b/platform/platform-impl/src/com/intellij/internal/statistic/service/fus/collectors/FUCounterUsageLogger.java @@ -8,6 +8,7 @@ import com.intellij.internal.statistic.eventLog.FeatureUsageGroup; import com.intellij.internal.statistic.eventLog.FeatureUsageLogger; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,7 +49,10 @@ public class FUCounterUsageLogger { } for (CounterUsageCollectorEP ep : CounterUsageCollectorEP.EP_NAME.getExtensionList()) { - register(new FeatureUsageGroup(ep.groupID, ep.version)); + final String id = ep.getGroupId(); + if (StringUtil.isNotEmpty(id)) { + register(new FeatureUsageGroup(id, ep.version)); + } } JobScheduler.getScheduler().scheduleWithFixedDelay( diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index cbc7ba45f2e9..ac63d8ae7bd1 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -439,11 +439,11 @@ - - - - - + + + + + From 47fd71ed43e61bf7d3e2dfaf7e7d8fb41be955f7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Feb 2019 20:06:31 +0100 Subject: [PATCH 095/138] IDEA-CR-42816 error only in test mode --- .../src/com/intellij/util/ExtensionInstantiator.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java index 9aabc178fd20..ee650961b563 100644 --- a/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java +++ b/platform/core-api/src/com/intellij/util/ExtensionInstantiator.java @@ -2,6 +2,8 @@ package com.intellij.util; import com.intellij.diagnostic.PluginException; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.AbstractExtensionPointBean; import com.intellij.openapi.extensions.PluginDescriptor; @@ -42,7 +44,14 @@ public final class ExtensionInstantiator { } catch (Throwable e) { if (e.getCause() instanceof NoSuchMethodException) { - LOG.error(new PluginException("Bean extension class constructor must not have parameters: " + className, pluginId)); + PluginException exception = new PluginException("Bean extension class constructor must not have parameters: " + className, pluginId); + Application app = ApplicationManager.getApplication(); + if (app != null && app.isUnitTestMode()) { + LOG.error(exception); + } + else { + LOG.warn(exception); + } } else { throw new PluginException(e, pluginId); From 2ce2a314ecfe5113644e6b288a6512317e521201 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Feb 2019 17:22:37 +0100 Subject: [PATCH 096/138] diagnostics for EA-135903 - assert: IFileElementType.parseContents --- .../src/com/intellij/psi/tree/IFileElementType.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java index af5f788cf723..474077f815d6 100644 --- a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java @@ -44,8 +44,12 @@ public class IFileElementType extends ILazyParseableElementType { @Nullable @Override public ASTNode parseContents(@NotNull final ASTNode chameleon) { - final PsiElement psi = chameleon.getPsi(); - assert psi != null : "Bad chameleon: " + chameleon; + PsiElement psi = chameleon.getPsi(); + if (psi == null) { + throw new AssertionError("Bad chameleon: " + chameleon + + " of type " + chameleon.getElementType() + + " in #" + chameleon.getElementType().getLanguage()); + } return doParseContents(chameleon, psi); } } From 9fc2a1b96df821a8d58365763534e94f20da9fb9 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Feb 2019 20:25:26 +0100 Subject: [PATCH 097/138] don't wrap PCE --- .../impl/quickfix/ChangeMethodSignatureFromUsageFix.java | 4 ++++ .../src/com/intellij/psi/augment/PsiAugmentProvider.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java index e87f5e864110..01e36e1d1744 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java @@ -18,6 +18,7 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; @@ -320,6 +321,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig try { PsiUtil.ensureValidType(bareParamType); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass( parameter.getClass() + "; valid=" + parameter.isValid() + "; method.valid=" + targetMethod.isValid(), diff --git a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java index 6b9043a8d76f..dc46402a4bb4 100644 --- a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java +++ b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java @@ -87,6 +87,9 @@ public abstract class PsiAugmentProvider { try { PsiUtil.ensureValidType(type); } + catch (ProcessCanceledException e) { + throw e; + } catch (Throwable e) { throw PluginException.createByClass(e, provider.getClass()); } From 780908b378f76447195d1924a69c94bae26af096 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Feb 2019 20:25:58 +0100 Subject: [PATCH 098/138] diagnostics for EA-112406 - REWA: DumbServiceImpl.showModalProgress --- .../openapi/project/DumbServiceImpl.java | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index afa44d86da2a..ac31d54967f9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -2,6 +2,7 @@ package com.intellij.openapi.project; import com.google.common.annotations.VisibleForTesting; +import com.intellij.diagnostic.ThreadDumper; import com.intellij.ide.IdeBundle; import com.intellij.ide.file.BatchFileChangeListener; import com.intellij.openapi.Disposable; @@ -454,6 +455,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica return; } while (isDumb()) { + assertState(State.SCHEDULED_TASKS); showModalProgress(); } } @@ -461,22 +463,34 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica private void showModalProgress() { NoAccessDuringPsiEvents.checkCallContext(); try { - ((ApplicationImpl)ApplicationManager.getApplication()).executeSuspendingWriteAction(myProject, IdeBundle.message("progress.indexing"), () -> - runBackgroundProcess(ProgressManager.getInstance().getProgressIndicator())); + ((ApplicationImpl)ApplicationManager.getApplication()).executeSuspendingWriteAction(myProject, IdeBundle.message("progress.indexing"), () -> { + assertState(State.SCHEDULED_TASKS); + runBackgroundProcess(ProgressManager.getInstance().getProgressIndicator()); + assertState(State.SMART, State.WAITING_FOR_FINISH); + }); + assertState(State.SMART, State.WAITING_FOR_FINISH); } finally { if (myState.get() != State.SMART) { - assertWeAreWaitingToFinish(); + assertState(State.WAITING_FOR_FINISH); updateFinished(); + assertState(State.SMART, State.SCHEDULED_TASKS); } } } - private void assertWeAreWaitingToFinish() { - final State state = myState.get(); - if (state != State.WAITING_FOR_FINISH) { - Attachment[] attachments = myDumbEnterTrace != null ? new Attachment[]{new Attachment("indexingStart", myDumbEnterTrace)} : Attachment.EMPTY_ARRAY; - throw new RuntimeExceptionWithAttachments(state.toString(), attachments); + private void assertState(State... expected) { + State state = myState.get(); + List expectedList = Arrays.asList(expected); + if (!expectedList.contains(state)) { + List attachments = new ArrayList<>(); + if (myDumbEnterTrace != null) { + attachments.add(new Attachment("indexingStart", myDumbEnterTrace)); + } + attachments.add(new Attachment("threadDump.txt", ThreadDumper.dumpThreadsToString())); + throw new RuntimeExceptionWithAttachments("Internal error, please include thread dump attachment. " + + "Expected " + expectedList + ", but was " + state.toString(), + attachments.toArray(Attachment.EMPTY_ARRAY)); } } From 47ae028a0e49f603cc0e64dc023fe831276221a6 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 20:30:21 +0100 Subject: [PATCH 099/138] FUS: update attribute for counter collectors (IDEA-CR-42556) --- .../src/META-INF/ExternalSystemExtensions.xml | 2 +- platform/platform-resources/src/META-INF/JsonPlugin.xml | 2 +- platform/platform-resources/src/META-INF/LangExtensions.xml | 4 ++-- platform/platform-resources/src/META-INF/xdebugger.xml | 2 +- platform/vcs-log/impl/src/META-INF/vcs-log.xml | 2 +- plugins/gradle/plugin-resources/META-INF/plugin.xml | 2 +- plugins/maven/src/main/resources/META-INF/plugin.xml | 2 +- plugins/terminal/resources/META-INF/terminal.xml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml index 5e8864721e9c..2729a2a8d2a2 100644 --- a/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml +++ b/platform/platform-resources/src/META-INF/ExternalSystemExtensions.xml @@ -81,7 +81,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index 7a286a8e9189..af07db91ced9 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -100,7 +100,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ea1d95a1ecca..a518075f4bc6 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -954,8 +954,8 @@ - - + + diff --git a/platform/platform-resources/src/META-INF/xdebugger.xml b/platform/platform-resources/src/META-INF/xdebugger.xml index 95cfa203a0f0..cbc5e89578eb 100644 --- a/platform/platform-resources/src/META-INF/xdebugger.xml +++ b/platform/platform-resources/src/META-INF/xdebugger.xml @@ -50,7 +50,7 @@ - + diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml index 3d6df26e6762..d935605aea2b 100644 --- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml +++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml @@ -30,7 +30,7 @@ - + diff --git a/plugins/gradle/plugin-resources/META-INF/plugin.xml b/plugins/gradle/plugin-resources/META-INF/plugin.xml index 8c937cb00d62..819d6e60d5d5 100644 --- a/plugins/gradle/plugin-resources/META-INF/plugin.xml +++ b/plugins/gradle/plugin-resources/META-INF/plugin.xml @@ -117,7 +117,7 @@ - + diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml index 7b879375074f..0ef2e872f248 100644 --- a/plugins/maven/src/main/resources/META-INF/plugin.xml +++ b/plugins/maven/src/main/resources/META-INF/plugin.xml @@ -196,7 +196,7 @@ - + diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml index ab7092da6734..f0971eda127b 100644 --- a/plugins/terminal/resources/META-INF/terminal.xml +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -15,7 +15,7 @@ - + From 6823df28301df0a7edfb0f5d952d81a1818a8f26 Mon Sep 17 00:00:00 2001 From: "Svetlana.Zemlyanskaya" Date: Mon, 4 Feb 2019 20:40:03 +0100 Subject: [PATCH 100/138] FUS: disable customization for dialog recording --- .../intellij/openapi/ui/DialogWrapper.java | 27 ++++++++++--------- .../customize/CustomizeIDEWizardDialog.java | 5 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index f615532188b6..e502a2b1cef5 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -1784,27 +1784,30 @@ public abstract class DialogWrapper { } private void logCloseDialogEvent(int exitCode) { - final String dialogId = getLoggedDialogId(); - if (StringUtil.isNotEmpty(dialogId)) { - FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(dialogId, exitCode, getClass()); + final boolean canRecord = canRecordDialogId(); + if (canRecord) { + final String dialogId = getClass().getName(); + if (StringUtil.isNotEmpty(dialogId)) { + FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(dialogId, exitCode, getClass()); + } } } private void logShowDialogEvent() { - final String dialogId = getLoggedDialogId(); - if (StringUtil.isNotEmpty(dialogId)) { - FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(dialogId, getClass()); + final boolean canRecord = canRecordDialogId(); + if (canRecord) { + final String dialogId = getClass().getName(); + if (StringUtil.isNotEmpty(dialogId)) { + FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(dialogId, getClass()); + } } } /** - * The ID will be recorded in user event log, it can be used to understand how often this dialog is used. - * - * @return null if we shouldn't record the dialog. + * If dialog open/close events should be recorded in user event log, it can be used to understand how often this dialog is used. */ - @Nullable - protected String getLoggedDialogId() { - return getClass().getName(); + protected boolean canRecordDialogId() { + return true; } /** diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java index b8a5306a7e9b..f3eab64c4790 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java @@ -180,10 +180,9 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis super.doOKAction(); } - @Nullable @Override - protected String getLoggedDialogId() { - return null; + protected boolean canRecordDialogId() { + return false; } private void initCurrentStep(boolean forward) { From fde40b00d3eb41436ba01828df29ab50230b827e Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Mon, 4 Feb 2019 20:01:44 +0300 Subject: [PATCH 101/138] remove redundant modifiers --- java/compiler/tests/com/intellij/compiler/IOUtilTest.java | 2 +- .../src/com/intellij/ide/PsiActionSupportFactory.java | 2 +- .../src/com/intellij/openapi/wm/AppIconScheme.java | 6 +++--- platform/platform-api/src/com/intellij/ui/ListUtil.java | 4 ++-- .../src/com/intellij/ui/ReorderableListController.java | 2 +- .../remoteServer/agent/util/log/TerminalListener.java | 2 +- .../intellij/util/containers/ConcurrentLongObjectMap.java | 2 +- .../connections/ssh/SmPublicKeyAuthentification.java | 4 ++-- .../intellij/openapi/cvsIntegration/DateOrRevision.java | 8 ++++---- .../cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java | 2 +- .../devkit/devkit-core/src/dom/generator/FileManager.java | 4 ++-- .../gradle/service/project/ProjectResolverContext.java | 2 +- .../groovy/lang/psi/api/types/GrTypeParameter.java | 2 +- .../lang/psi/impl/synthetic/GrDynamicImplicitElement.java | 8 ++++---- .../xsltDebugger/rt/engine/remote/RemoteDebugger.java | 2 +- .../python/debugger/pydev/PyVariableLocator.java | 4 ++-- .../com/jetbrains/python/run/RunnableScriptFilter.java | 2 +- .../pytestLegacy/PyTestRunConfigurationParams.java | 8 ++++---- .../tests/com/intellij/util/xml/DomExtensionsTest.java | 2 +- .../tests/com/intellij/util/xml/DomSimpleValuesTest.java | 3 +-- .../plugins/relaxNG/compact/psi/impl/FollowFileHint.java | 2 +- .../org/intellij/plugins/relaxNG/model/CommonElement.java | 2 +- 22 files changed, 37 insertions(+), 38 deletions(-) diff --git a/java/compiler/tests/com/intellij/compiler/IOUtilTest.java b/java/compiler/tests/com/intellij/compiler/IOUtilTest.java index 713aac1f5da1..f17be223b042 100644 --- a/java/compiler/tests/com/intellij/compiler/IOUtilTest.java +++ b/java/compiler/tests/com/intellij/compiler/IOUtilTest.java @@ -14,7 +14,7 @@ import java.io.*; */ public class IOUtilTest extends TestCase { - private static interface IO { + private interface IO { void save(String str, DataOutput out) throws IOException; String load(DataInput in) throws IOException; } diff --git a/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java b/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java index 65bb3b88b0ec..de8e3007f8ce 100644 --- a/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java +++ b/platform/lang-api/src/com/intellij/ide/PsiActionSupportFactory.java @@ -31,7 +31,7 @@ public abstract class PsiActionSupportFactory { return ServiceManager.getService(PsiActionSupportFactory.class); } - public static interface PsiElementSelector { + public interface PsiElementSelector { @NotNull PsiElement[] getSelectedElements(); } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java b/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java index 2ee5e36fa467..52345dc1df53 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/AppIconScheme.java @@ -26,7 +26,7 @@ public class AppIconScheme { public interface Progress { - static final Progress TESTS = new Progress() { + Progress TESTS = new Progress() { @Override public Color getOkColor() { return TESTS_OK_COLOR; @@ -38,7 +38,7 @@ public class AppIconScheme { } }; - static final Progress BUILD = new Progress() { + Progress BUILD = new Progress() { @Override public Color getOkColor() { return BUILD_OK_COLOR; @@ -50,7 +50,7 @@ public class AppIconScheme { } }; - static final Progress INDEXING = new Progress() { + Progress INDEXING = new Progress() { @Override public Color getOkColor() { return INDEXING_OK_COLOR; diff --git a/platform/platform-api/src/com/intellij/ui/ListUtil.java b/platform/platform-api/src/com/intellij/ui/ListUtil.java index de942516d0fd..5492a49eb323 100644 --- a/platform/platform-api/src/com/intellij/ui/ListUtil.java +++ b/platform/platform-api/src/com/intellij/ui/ListUtil.java @@ -335,7 +335,7 @@ public class ListUtil { return listener; } - public static interface RemoveNotification { + public interface RemoveNotification { void itemsRemoved(List items); } @@ -350,7 +350,7 @@ public class ListUtil { return null; } - private static interface ListModelExtension { + private interface ListModelExtension { Object get(ModelType model, int index); void remove(ModelType model, int index); } diff --git a/platform/platform-api/src/com/intellij/ui/ReorderableListController.java b/platform/platform-api/src/com/intellij/ui/ReorderableListController.java index 5f6689939c8b..f610e8a053e6 100644 --- a/platform/platform-api/src/com/intellij/ui/ReorderableListController.java +++ b/platform/platform-api/src/com/intellij/ui/ReorderableListController.java @@ -196,7 +196,7 @@ public abstract class ReorderableListController { } } - static interface ActionBehaviour { + interface ActionBehaviour { T performAction(@NotNull AnActionEvent e); void updateAction(@NotNull AnActionEvent e); } diff --git a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java index bd1590b00cb8..30f3be67e29b 100644 --- a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java +++ b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/log/TerminalListener.java @@ -19,7 +19,7 @@ public interface TerminalListener { void close(); - static TerminalListener NULL = new TerminalListener() { + TerminalListener NULL = new TerminalListener() { public void close() { diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java index db992680c023..a848c7284bcb 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentLongObjectMap.java @@ -82,7 +82,7 @@ public interface ConcurrentLongObjectMap { boolean isEmpty(); @NotNull - public Enumeration elements(); + Enumeration elements(); @NotNull Collection values(); boolean containsValue(@NotNull V value); diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java index d232ef29b4a1..405f743ea79e 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ssh/SmPublicKeyAuthentification.java @@ -19,6 +19,6 @@ package com.intellij.cvsSupport2.connections.ssh; * author: lesya */ public interface SmPublicKeyAuthentification { - public Throwable PRIVATE_KEY_FILE = new Throwable(); - public Throwable PASSPHRASE = new Throwable(); + Throwable PRIVATE_KEY_FILE = new Throwable(); + Throwable PASSPHRASE = new Throwable(); } diff --git a/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java b/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java index 798261a74cbb..5b32a58f806d 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java +++ b/plugins/cvs/cvs-core/src/com/intellij/openapi/cvsIntegration/DateOrRevision.java @@ -17,8 +17,8 @@ package com.intellij.openapi.cvsIntegration; public interface DateOrRevision { - public String getBranch(); - public boolean shouldUseBranch(); - public String getDate(); - public boolean shouldUseDate(); + String getBranch(); + boolean shouldUseBranch(); + String getDate(); + boolean shouldUseDate(); } diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java index 0e24b73a4b78..640748ddeaa1 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/CvsUtil.java @@ -727,7 +727,7 @@ public class CvsUtil { return dirTag.startsWith(STICKY_BRANCH_TAG_PREFIX) || dirTag.startsWith(STICKY_NON_BRANCH_TAG_PREFIX); } - private static interface FileCondition { + private interface FileCondition { boolean verify(File file); } diff --git a/plugins/devkit/devkit-core/src/dom/generator/FileManager.java b/plugins/devkit/devkit-core/src/dom/generator/FileManager.java index 8ad5c711a6c4..b82843d7f769 100644 --- a/plugins/devkit/devkit-core/src/dom/generator/FileManager.java +++ b/plugins/devkit/devkit-core/src/dom/generator/FileManager.java @@ -28,6 +28,6 @@ import java.io.File; * @author Konstantin Bulenkov */ public interface FileManager { - public File releaseOutputFile(File outFile); - public File getOutputFile(File target); + File releaseOutputFile(File outFile); + File getOutputFile(File target); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java index 8c481629a857..1f16b05fc47e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java @@ -63,7 +63,7 @@ public interface ProjectResolverContext extends UserDataHolderEx { @NotNull ProjectImportAction.AllModels getModels(); - public void setModels(@NotNull ProjectImportAction.AllModels models) ; + void setModels(@NotNull ProjectImportAction.AllModels models) ; @Nullable T getExtraProject(Class modelClazz); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java index 13d820e3f66e..dd4fd39f505f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/types/GrTypeParameter.java @@ -24,6 +24,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini * @author ilyas */ public interface GrTypeParameter extends GrTypeDefinition, PsiTypeParameter { - public static final GrTypeParameter[] EMPTY_ARRAY = new GrTypeParameter[0]; + GrTypeParameter[] EMPTY_ARRAY = new GrTypeParameter[0]; ArrayFactory ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new GrTypeParameter[count]; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java index 4cc754136aa4..134004b5e542 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrDynamicImplicitElement.java @@ -29,12 +29,12 @@ import org.jetbrains.annotations.Nullable; */ public interface GrDynamicImplicitElement extends ItemPresentation, NavigationItem { @Nullable - public PsiClass getContainingClassElement(); + PsiClass getContainingClassElement(); @NotNull - public SearchScope getUseScope(); + SearchScope getUseScope(); - public PsiFile getContainingFile(); + PsiFile getContainingFile(); - public String getContainingClassName(); + String getContainingClassName(); } diff --git a/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java b/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java index 510d24e5cbdf..255742575a01 100644 --- a/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java +++ b/plugins/xslt-debugger/engine/src/org/intellij/plugins/xsltDebugger/rt/engine/remote/RemoteDebugger.java @@ -83,7 +83,7 @@ public interface RemoteDebugger extends Remote { String getInstruction() throws RemoteException; } - public interface Variable extends Remote { + interface Variable extends Remote { boolean isGlobal() throws RemoteException; Debugger.Variable.Kind getKind() throws RemoteException; diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java index 3ba4e1cd96de..293f71dc5363 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java @@ -10,8 +10,8 @@ package com.jetbrains.python.debugger.pydev; */ public interface PyVariableLocator { - public String getThreadId(); + String getThreadId(); - public String getPyDBLocation(); + String getPyDBLocation(); } diff --git a/python/src/com/jetbrains/python/run/RunnableScriptFilter.java b/python/src/com/jetbrains/python/run/RunnableScriptFilter.java index 6f81eba3158e..0f48516ed083 100644 --- a/python/src/com/jetbrains/python/run/RunnableScriptFilter.java +++ b/python/src/com/jetbrains/python/run/RunnableScriptFilter.java @@ -38,7 +38,7 @@ public interface RunnableScriptFilter { boolean isRunnableScript(PsiFile script, @NotNull Module module, Location location, @Nullable TypeEvalContext context); - public static boolean isIfNameMain(Location location) { + static boolean isIfNameMain(Location location) { PsiElement element = location.getPsiElement(); while (true) { final PyIfStatement ifStatement = PsiTreeUtil.getParentOfType(element, PyIfStatement.class); diff --git a/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java b/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java index 6f40141b0cb9..ce9864308263 100644 --- a/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java +++ b/python/src/com/jetbrains/python/testing/pytestLegacy/PyTestRunConfigurationParams.java @@ -19,8 +19,8 @@ package com.jetbrains.python.testing.pytestLegacy; * User : catherine */ public interface PyTestRunConfigurationParams { - public boolean useParam(); - public void useParam(boolean useParam); - public boolean useKeyword(); - public void useKeyword(boolean useKeyword); + boolean useParam(); + void useParam(boolean useParam); + boolean useKeyword(); + void useKeyword(boolean useKeyword); } diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java index e68e16b0278f..b8a577b06820 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomExtensionsTest.java @@ -295,6 +295,6 @@ public class DomExtensionsTest extends DomTestCase { public MyStringBufferConverter(boolean b) { } } - public static interface MyAttribute extends GenericAttributeValue {} + public interface MyAttribute extends GenericAttributeValue {} } diff --git a/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java b/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java index 79ae28680b23..4c4650648e3f 100644 --- a/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java +++ b/xml/dom-tests/tests/com/intellij/util/xml/DomSimpleValuesTest.java @@ -15,7 +15,6 @@ */ package com.intellij.util.xml; -import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -532,7 +531,7 @@ public class DomSimpleValuesTest extends DomTestCase { public interface CmpField extends JavaeeDomModelElement { @NameValue - public GenericDomValue getName(); + GenericDomValue getName(); } public static class MyConverter extends Converter { diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java index 3ea00daf9f69..e0cafccf71ad 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/compact/psi/impl/FollowFileHint.java @@ -22,5 +22,5 @@ import org.intellij.plugins.relaxNG.compact.psi.RncFile; public interface FollowFileHint { Key KEY = Key.create("FollowFileHint"); - public boolean doFollow(RncFile file); + boolean doFollow(RncFile file); } diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java index 095b66165396..6ae76e41b2fe 100644 --- a/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java +++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/model/CommonElement.java @@ -27,7 +27,7 @@ public interface CommonElement { @Nullable E getPsiElement(); - static abstract class Visitor { + abstract class Visitor { public void visitElement(CommonElement pattern) { } From 509bdf8cd5086ec0bdecb266f681085853014f10 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Mon, 4 Feb 2019 23:05:11 +0300 Subject: [PATCH 102/138] Make common toolwindow gear actions true dumbaware (actions are combined in action groups and these groups also has to be dumbaware) --- .../src/com/intellij/ide/actions/ToolWindowMoveAction.java | 5 +++++ .../com/intellij/ide/actions/ToolWindowViewModeAction.java | 5 +++++ .../com/intellij/openapi/wm/impl/InternalDecorator.java | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java index f7f2280f1aa3..31e5b1300db8 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowMoveAction.java @@ -144,6 +144,11 @@ public class ToolWindowMoveAction extends DumbAwareAction { super(UIBundle.message("tool.window.move.to.action.group.name"), true); } + @Override + public boolean isDumbAware() { + return true; + } + @Override public void update(@NotNull AnActionEvent e) { if (!isInitialized) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java index e9a4164d25d6..9b5d5bbb450d 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/ToolWindowViewModeAction.java @@ -147,6 +147,11 @@ public class ToolWindowViewModeAction extends DumbAwareToggleAction { super(ActionsBundle.groupText("ViewMode"), true); } + @Override + public boolean isDumbAware() { + return true; + } + @Override public void update(@NotNull AnActionEvent e) { if (!isInitialized) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java index bc1348e4f3cd..ab371edfd51c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java @@ -421,7 +421,12 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr @NotNull private DefaultActionGroup createResizeActionGroup() { - DefaultActionGroup resize = new DefaultActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true); + DefaultActionGroup resize = new DefaultActionGroup(ActionsBundle.groupText("ResizeToolWindowGroup"), true) { + @Override + public boolean isDumbAware() { + return true; + } + }; resize.add(new ResizeToolWindowAction.Left(myToolWindow, this)); resize.add(new ResizeToolWindowAction.Right(myToolWindow, this)); resize.add(new ResizeToolWindowAction.Up(myToolWindow, this)); From 8a93419958783e24170a043594272598af168aaf Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 4 Feb 2019 19:41:08 +0300 Subject: [PATCH 103/138] add "intellij.platform.debugger.testFramework" to modules.xml follow-up: e01afe9f316b1c82847325077757556aa3517010 --- .idea/modules.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/modules.xml b/.idea/modules.xml index 1556bf9451d6..494ceb46dbb2 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -565,6 +565,7 @@ + From 676222ea73c409296015bb4e400ce3b7b14d28b4 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Mon, 4 Feb 2019 23:16:52 +0300 Subject: [PATCH 104/138] use `collection.addAll` instead of `for (...) {collection.add(it)}` --- .../util/xml/converters/ClassArrayConverterImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java b/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java index a7e2dd308fcd..07ace6f972b1 100644 --- a/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java +++ b/java/java-impl/src/com/intellij/util/xml/converters/ClassArrayConverterImpl.java @@ -25,6 +25,7 @@ import com.intellij.util.xml.converters.values.ClassArrayConverter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class ClassArrayConverterImpl extends ClassArrayConverter { @@ -66,10 +67,7 @@ public class ClassArrayConverterImpl extends ClassArrayConverter { } private static void createReference(final PsiElement element, final String s, final int offset, List list) { - final PsiReference[] references = REFERENCE_PROVIDER.getReferencesByString(s, element, offset); - //noinspection ManualArrayToCollectionCopy - for (PsiReference ref: references) { - list.add(ref); - } + PsiReference[] references = REFERENCE_PROVIDER.getReferencesByString(s, element, offset); + list.addAll(Arrays.asList(references)); } } From ab08ceeb6aa3d9a9a4ee7e5a39f85b7a9f314d39 Mon Sep 17 00:00:00 2001 From: Alexander Kirillin Date: Wed, 16 Jan 2019 17:42:58 +0300 Subject: [PATCH 105/138] CPP-15144 Go to declaration doesn't work for closing override braces --- .../src/com/intellij/codeInsight/TargetElementUtil.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java index fc7d1907bd46..754f825071ae 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/TargetElementUtil.java @@ -116,9 +116,13 @@ public class TargetElementUtil extends TargetElementUtilBase { PsiReference ref = file.findReferenceAt(adjustOffset(file, document, offset)); if (ref == null) return null; int elementOffset = ref.getElement().getTextRange().getStartOffset(); - if (ref.getRangeInElement().shiftRight(elementOffset).containsOffset(offset)) { - return ref; + + for (TextRange range : ReferenceRange.getRanges(ref)) { + if (range.shiftRight(elementOffset).containsOffset(offset)) { + return ref; + } } + return null; } From eeb77af665713f954f856463cd5fee7aafa97afa Mon Sep 17 00:00:00 2001 From: Alexander Kirillin Date: Fri, 18 Jan 2019 19:53:19 +0300 Subject: [PATCH 106/138] CPP-15168 Mark inspections, available when clangd is off --- .../inspectionsTree/InspectionToolWrapperWithHint.java | 9 +++++++++ .../inspectionsTree/InspectionsConfigTreeRenderer.java | 4 ++++ 2 files changed, 13 insertions(+) create mode 100644 platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java new file mode 100644 index 000000000000..781f98aaf97a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionToolWrapperWithHint.java @@ -0,0 +1,9 @@ +// Copyright 2000-2019 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.profile.codeInspection.ui.inspectionsTree; + +public interface InspectionToolWrapperWithHint { + /** + * Hint will be displayed in gray after inspection name + */ + String getHint(); +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java index 1266aa461505..28d886f50393 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java @@ -61,6 +61,10 @@ public abstract class InspectionsConfigTreeRenderer extends DefaultTreeRenderer @Nullable private static String getHint(final Descriptor descriptor) { final InspectionToolWrapper toolWrapper = descriptor.getToolWrapper(); + + if (toolWrapper.getTool() instanceof InspectionToolWrapperWithHint) { + return ((InspectionToolWrapperWithHint)toolWrapper.getTool()).getHint(); + } if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper && !((GlobalInspectionToolWrapper)toolWrapper).worksInBatchModeOnly()) { return null; From 773aae2a3902942c46419f452eaffe8251bd1d82 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Mon, 4 Feb 2019 23:57:50 +0300 Subject: [PATCH 107/138] remove unused classes --- .../options/ProcessedModulesTable.java | 456 ------------------ .../generic/VirtualFilePersistentState.java | 52 -- .../compiler/generic/VirtualFileSetState.java | 89 ---- 3 files changed, 597 deletions(-) delete mode 100644 java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java delete mode 100644 java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java delete mode 100644 java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java diff --git a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java b/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java deleted file mode 100644 index 580fbb60cf67..000000000000 --- a/java/compiler/impl/src/com/intellij/compiler/options/ProcessedModulesTable.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * 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 com.intellij.compiler.options; - -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleType; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.wm.IdeFocusManager; -import com.intellij.ui.SpeedSearchBase; -import com.intellij.ui.SpeedSearchComparator; -import com.intellij.ui.TableUtil; -import com.intellij.ui.ToolbarDecorator; -import com.intellij.ui.table.JBTable; -import com.intellij.util.ui.EditableModel; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.table.*; -import java.awt.*; -import java.util.List; -import java.util.*; - -public class ProcessedModulesTable extends JPanel { - private JBTable myTable = null; - private MyTableModel myTableModel = null; - - public ProcessedModulesTable(final Project project) { - super(new BorderLayout()); - - myTableModel = new MyTableModel(project); - myTable = new JBTable(myTableModel); - myTable.getEmptyText().setText("No modules configured"); - - //myTable.setShowGrid(false); - myTable.setIntercellSpacing(JBUI.emptySize()); - myTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); - myTable.setColumnSelectionAllowed(false); - - final TableColumnModel columnModel = myTable.getColumnModel(); - - final TableColumn dirNameColumn = columnModel.getColumn(myTableModel.DIRNAME_COLUMN_INDEX); - final String title = "Generated Sources Directory Name"; - dirNameColumn.setHeaderValue(title); - final JTableHeader tableHeader = myTable.getTableHeader(); - final FontMetrics metrics = tableHeader.getFontMetrics(tableHeader.getFont()); - final int preferredWidth = metrics.stringWidth(title) + 12; - dirNameColumn.setPreferredWidth(preferredWidth); - dirNameColumn.setMaxWidth(preferredWidth + 20); - dirNameColumn.setCellRenderer(new MyElementColumnCellRenderer()); - - final TableColumn moduleColumn = columnModel.getColumn(myTableModel.ELEMENT_COLUMN_INDEX); - moduleColumn.setHeaderValue("Module"); - moduleColumn.setCellRenderer(new MyElementColumnCellRenderer()); - - final JPanel panel = ToolbarDecorator.createDecorator(myTable) - .disableUpDownActions() - .setPreferredSize(JBUI.size(100, 155)) - .createPanel(); - add(panel, BorderLayout.CENTER); - - final SpeedSearchBase speedSearch = new SpeedSearchBase(myTable) { - @Override - public int getSelectedIndex() { - return myTable.getSelectedRow(); - } - - @Override - protected int convertIndexToModel(int viewIndex) { - return myTable.convertRowIndexToModel(viewIndex); - } - - @NotNull - @Override - public Object[] getAllElements() { - final int count = myTableModel.getRowCount(); - Object[] elements = new Object[count]; - for (int idx = 0; idx < count; idx++) { - elements[idx] = myTableModel.getModuleAt(idx); - } - return elements; - } - - @Override - public String getElementText(Object element) { - return ((Module)element).getName() + " (" + FileUtil.toSystemDependentName(((Module)element).getModuleFilePath()) + ")"; - } - - @Override - public void selectElement(Object element, String selectedText) { - final int count = myTableModel.getRowCount(); - for (int row = 0; row < count; row++) { - if (element.equals(myTableModel.getModuleAt(row))) { - final int viewRow = myTable.convertRowIndexToView(row); - myTable.getSelectionModel().setSelectionInterval(viewRow, viewRow); - TableUtil.scrollSelectionToVisible(myTable); - break; - } - } - } - }; - speedSearch.setComparator(new SpeedSearchComparator(false)); - } - - public void refresh() { - myTableModel.fireTableDataChanged(); - } - - public void refresh(Module element) { - final int row = myTableModel.getElementRow(element); - if (row >= 0) { - myTableModel.fireTableRowsUpdated(row, row); - } - } - - private int[] mySavedSelection = null; - public void saveSelection() { - mySavedSelection = myTable.getSelectedRows(); - } - - public void restoreSelection() { - if (mySavedSelection != null) { - TableUtil.selectRows(myTable, mySavedSelection); - mySavedSelection = null; - } - } - - public void addModule(Module element, String dirName) { - myTableModel.addElement(element, dirName); - selectRow(myTableModel.getRowCount() - 1); - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - public void removeModule(Module element) { - final int elementRow = myTableModel.getElementRow(element); - if (elementRow < 0) { - return; // no such element - } - final boolean wasSelected = myTable.getSelectionModel().isSelectedIndex(elementRow); - - myTableModel.removeElement(element); - - if (wasSelected) { - final int rowCount = myTableModel.getRowCount(); - if (rowCount > 0) { - selectRow(elementRow % rowCount); - } - else { - myTable.getSelectionModel().clearSelection(); - } - } - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - public void removeAllElements() { - myTableModel.removeAllElements(); - myTable.getSelectionModel().clearSelection(); - } - - private void selectRow(final int row) { - myTable.getSelectionModel().setSelectionInterval(row, row); - myTable.scrollRectToVisible(myTable.getCellRect(row, 0, true)); - } - - @Nullable - public Module getSelectedElement() { - final int selectedRow = getSelectedElementRow(); - return selectedRow < 0? null : myTableModel.getModuleAt(selectedRow); - } - - public int getSelectedElementRow() { - return myTable.getSelectedRow(); - } - - public List getSelectedElements() { - final List elements = new ArrayList<>(); - final int[] selectedRows = myTable.getSelectedRows(); - for (int selectedRow : selectedRows) { - if (selectedRow < 0) { - continue; - } - elements.add(myTableModel.getModuleAt(selectedRow)); - } - return elements; - } - - public void selectElements(Collection elements) { - if (elements.size() == 0) { - myTable.clearSelection(); - return; - } - final int[] rows = getElementsRows(elements); - TableUtil.selectRows(myTable, rows); - TableUtil.scrollSelectionToVisible(myTable); - IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myTable, true)); - } - - private int[] getElementsRows(final Collection elements) { - final int[] rows = new int[elements.size()]; - int index = 0; - for (final Module element : elements) { - rows[index++] = myTableModel.getElementRow(element); - } - return rows; - } - - public List> getAllModules() { - final int count = myTableModel.getRowCount(); - List> elements = new ArrayList<>(); - for (int idx = 0; idx < count; idx++) { - final Module module = myTableModel.getModuleAt(idx); - elements.add(Pair.create(module, myTableModel.getGenDirName(module))); - } - return elements; - } - - public void sort(Comparator comparator) { - myTableModel.sort(comparator); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - myTable.setRowSelectionAllowed(enabled); - myTableModel.fireTableDataChanged(); - } - - public void stopEditing() { - TableCellEditor editor = myTable.getCellEditor(); - if (editor != null) { - editor.stopCellEditing(); - } - } - - public JComponent getComponent() { - return myTable; - } - - public void clear() { - myTableModel.clear(); - } - - public int getElementCount() { - return myTableModel.getRowCount(); - } - - public Module getElementAt(int row) { - return myTableModel.getModuleAt(row); - } - - private final class MyTableModel extends AbstractTableModel implements EditableModel { - private final List myElements = new ArrayList<>(); - private final Map myDirNameMap = new HashMap<>(); - public final int ELEMENT_COLUMN_INDEX = 0; - public final int DIRNAME_COLUMN_INDEX = 1; - private final Project myProject; - - private MyTableModel(Project project) { - myProject = project; - } - - public void sort(Comparator comparator) { - Collections.sort(myElements, comparator); - fireTableDataChanged(); - } - - public List getAllModules() { - return Collections.unmodifiableList(myElements); - } - - public Module getModuleAt(int index) { - return myElements.get(index); - } - - public String getGenDirName(Module module) { - return myDirNameMap.get(module); - } - - void addElement(Module module, final String dirName) { - myElements.add(module); - if (dirName != null && dirName.length() > 0) { - myDirNameMap.put(module, dirName); - } - int row = myElements.size() - 1; - fireTableRowsInserted(row, row); - } - - @Override - public void addRow() { - final Set projectModules = new HashSet<>(Arrays.asList(ModuleManager.getInstance(myProject).getModules())); - projectModules.removeAll(getAllModules()); - final ChooseModulesDialog chooser = - new ChooseModulesDialog(ProcessedModulesTable.this, new ArrayList<>(projectModules), "ChooseModule"); - if (chooser.showAndGet()) { - final List chosen = chooser.getChosenElements(); - for (Module module : chosen) { - addElement(module, null); - } - } - } - - @Override - public void removeRow(int idx) { - final Module element = myElements.remove(idx); - myDirNameMap.remove(element); - fireTableRowsDeleted(idx, idx); - } - - @Override - public void exchangeRows(int oldIndex, int newIndex) { - } - - @Override - public boolean canExchangeRows(int oldIndex, int newIndex) { - return false; - } - - public void removeElement(Module element) { - final boolean reallyRemoved = myElements.remove(element); - if (reallyRemoved) { - myDirNameMap.remove(element); - fireTableDataChanged(); - } - } - - public int getElementRow(Module element) { - return myElements.indexOf(element); - } - - public void removeAllElements() { - myElements.clear(); - fireTableDataChanged(); - } - - @Override - public int getRowCount() { - return myElements.size(); - } - - @Override - public int getColumnCount() { - return 2; - } - - @Override - @Nullable - public Object getValueAt(int rowIndex, int columnIndex) { - Module element = myElements.get(rowIndex); - if (columnIndex == ELEMENT_COLUMN_INDEX) { - return element; - } - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return myDirNameMap.get(element); - } - return null; - } - - @Override - public void setValueAt(Object value, int rowIndex, int columnIndex) { - if (columnIndex == DIRNAME_COLUMN_INDEX) { - final Module module = myElements.get(rowIndex); - if (value != null) { - String dir = FileUtil.toSystemIndependentName((String)value); - while (dir.startsWith("/")) { - dir = dir.substring(1); - } - if (dir.length() > 0) { - myDirNameMap.put(module, dir); - } - else { - myDirNameMap.remove(module); - } - } - else { - myDirNameMap.remove(module); - } - fireTableRowsUpdated(rowIndex, rowIndex); - } - } - - @Override - public Class getColumnClass(int columnIndex) { - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return String.class; - } - return super.getColumnClass(columnIndex); - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - if (!ProcessedModulesTable.this.isEnabled()) { - return false; - } - if (columnIndex == DIRNAME_COLUMN_INDEX) { - return true; - } - return false; - } - - public void clear() { - myElements.clear(); - myDirNameMap.clear(); - fireTableDataChanged(); - } - } - - private class MyElementColumnCellRenderer extends DefaultTableCellRenderer { - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - final Color color = UIUtil.getTableFocusCellBackground(); - Component component; - final Module module = value instanceof Module? (Module)value : null; - try { - UIManager.put(UIUtil.TABLE_FOCUS_CELL_BACKGROUND_PROPERTY, table.getSelectionBackground()); - component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (module != null) { - setText(module.getName() + " (" + FileUtil.toSystemDependentName(module.getModuleFilePath()) + ")"); - } - if (component instanceof JLabel) { - ((JLabel)component).setBorder(noFocusBorder); - } - } - finally { - UIManager.put(UIUtil.TABLE_FOCUS_CELL_BACKGROUND_PROPERTY, color); - } - component.setEnabled(ProcessedModulesTable.this.isEnabled()); - if (component instanceof JLabel) { - final Icon icon = module != null ? ModuleType.get(module).getIcon() : null; - JLabel label = (JLabel)component; - label.setIcon(icon); - label.setDisabledIcon(icon); - } - component.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); - return component; - } - } -} diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java deleted file mode 100644 index 17739b154aa6..000000000000 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFilePersistentState.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ -package com.intellij.openapi.compiler.generic; - -import com.intellij.util.io.DataExternalizer; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** -* @author nik -*/ -public class VirtualFilePersistentState { - public static DataExternalizer EXTERNALIZER = new VirtualFileStateExternalizer(); - private final long mySourceTimestamp; - - public VirtualFilePersistentState(long sourceTimestamp) { - mySourceTimestamp = sourceTimestamp; - } - - public final long getSourceTimestamp() { - return mySourceTimestamp; - } - - private static class VirtualFileStateExternalizer implements DataExternalizer { - @Override - public void save(@NotNull DataOutput out, VirtualFilePersistentState value) throws IOException { - out.writeLong(value.getSourceTimestamp()); - } - - @Override - public VirtualFilePersistentState read(@NotNull DataInput in) throws IOException { - return new VirtualFilePersistentState(in.readLong()); - } - - } -} diff --git a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java b/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java deleted file mode 100644 index 1dc4fe6e49ca..000000000000 --- a/java/compiler/impl/src/com/intellij/openapi/compiler/generic/VirtualFileSetState.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ -package com.intellij.openapi.compiler.generic; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.IOUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * @author nik - */ -public class VirtualFileSetState { - public static final DataExternalizer EXTERNALIZER = new VirtualFileWithDependenciesExternalizer(); - private final Map myTimestamps = new HashMap<>(); - - public VirtualFileSetState() { - } - - public VirtualFileSetState(Collection files) { - for (VirtualFile file : files) { - addFile(file); - } - } - - public void addFile(@NotNull VirtualFile file) { - myTimestamps.put(file.getUrl(), file.getTimeStamp()); - } - - public boolean isUpToDate(Set files) { - if (files.size() != myTimestamps.size()) { - return false; - } - - for (VirtualFile file : files) { - final Long timestamp = myTimestamps.get(file.getUrl()); - if (timestamp == null || timestamp != file.getTimeStamp()) { - return false; - } - } - return true; - } - - - private static class VirtualFileWithDependenciesExternalizer implements DataExternalizer { - @Override - public void save(@NotNull DataOutput out, VirtualFileSetState value) throws IOException { - final Map dependencies = value.myTimestamps; - out.writeInt(dependencies.size()); - for (Map.Entry entry : dependencies.entrySet()) { - IOUtil.writeUTF(out, entry.getKey()); - out.writeLong(entry.getValue()); - } - } - - @Override - public VirtualFileSetState read(@NotNull DataInput in) throws IOException { - final VirtualFileSetState state = new VirtualFileSetState(); - int size = in.readInt(); - while (size-- > 0) { - final String url = IOUtil.readUTF(in); - final long timestamp = in.readLong(); - state.myTimestamps.put(url, timestamp); - } - return state; - } - } -} From 943e37eb3e8d1dc70bbb70885452f52683b3af9d Mon Sep 17 00:00:00 2001 From: Artem Bochkarev Date: Fri, 1 Feb 2019 13:44:05 +0300 Subject: [PATCH 108/138] linux-menu: added possibility to disable key-event listening --- .../openapi/wm/impl/GlobalMenuLinux.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index f5ebb5b28d6d..509610864dee 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -103,14 +103,15 @@ interface GlobalMenuLib extends Library { public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final SimpleDateFormat ourDtf = new SimpleDateFormat("hhmmss.SSS"); // for debug only - private static final boolean TRACE_SYSOUT = System.getProperty("linux.native.menu.debug.trace.sysout", "false").equals("true"); - private static final boolean TRACE_DISABLED = System.getProperty("linux.native.menu.debug.trace.disabled", "true").equals("true"); - private static final boolean TRACE_SYNC_STATS = System.getProperty("linux.native.menu.debug.trace.sync-stats", "false").equals("true"); - private static final boolean TRACE_EVENTS = System.getProperty("linux.native.menu.debug.trace.events", "false").equals("true"); - private static final boolean TRACE_EVENT_FILTER = System.getProperty("linux.native.menu.debug.trace.event-filter", "false").equals("true"); - private static final boolean TRACE_CLEARING = System.getProperty("linux.native.menu.debug.trace.clearing", "false").equals("true"); - private static final boolean TRACE_HIERARCHY_MISMATCHES = System.getProperty("linux.native.menu.debug.trace.hierarchy.mismatches","false").equals("true"); - private static final boolean SHOW_SWING_MENU = System.getProperty("linux.native.menu.debug.show.frame.menu", "false").equals("true"); + private static final boolean TRACE_SYSOUT = Boolean.getBoolean("linux.native.menu.debug.trace.sysout"); + private static final boolean TRACE_ENABLED = Boolean.getBoolean("linux.native.menu.debug.trace.enabled"); + private static final boolean TRACE_SYNC_STATS = Boolean.getBoolean("linux.native.menu.debug.trace.sync-stats"); + private static final boolean TRACE_EVENTS = Boolean.getBoolean("linux.native.menu.debug.trace.events"); + private static final boolean TRACE_EVENT_FILTER = Boolean.getBoolean("linux.native.menu.debug.trace.event-filter"); + private static final boolean TRACE_CLEARING = Boolean.getBoolean("linux.native.menu.debug.trace.clearing"); + private static final boolean TRACE_HIERARCHY_MISMATCHES = Boolean.getBoolean("linux.native.menu.debug.trace.hierarchy.mismatches"); + private static final boolean SHOW_SWING_MENU = Boolean.getBoolean("linux.native.menu.debug.show.frame.menu"); + private static final boolean KDE_DISABLE_ROOT_MNEMONIC_PROCESSING = Boolean.getBoolean("linux.native.menu.kde.disable.root.mnemonic"); private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); private static final GlobalMenuLib ourLib; @@ -212,7 +213,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { ourInstances.remove(myXid); }; - if (SystemInfo.isKDE) { + if (SystemInfo.isKDE && !KDE_DISABLE_ROOT_MNEMONIC_PROCESSING) { // root menu items doesn't catch mnemonic shortcuts (in KDE), so process them inside IDE IdeEventQueue.getInstance().addDispatcher(e -> { if (!(e instanceof KeyEvent)) @@ -779,7 +780,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final int x11keycode = X11KeyCodes.jkeycode2X11code(jkeycode, 0); if (x11keycode != 0) ourLib.setItemShortcut(nativePeer, jmodifiers, x11keycode); - else if (!TRACE_DISABLED) + else if (TRACE_ENABLED) _trace("unknown x11 keycode for jcode=" + jkeycode); } } @@ -1023,14 +1024,14 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } private static void _trace(String fmt, Object... args) { - if (TRACE_DISABLED) + if (!TRACE_ENABLED) return; final String msg = String.format(fmt, args); _trace(msg); } private static void _trace(String msg) { - if (TRACE_DISABLED) + if (!TRACE_ENABLED) return; if (TRACE_SYSOUT) //noinspection UseOfSystemOutOrSystemErr From 1db8939ca5b12006b4a6b5aff6b224cdd8f8e626 Mon Sep 17 00:00:00 2001 From: Artem Bochkarev Date: Fri, 1 Feb 2019 15:45:20 +0300 Subject: [PATCH 109/138] linux-menu: minimize empty submenu showing --- .../openapi/wm/impl/GlobalMenuLinux.java | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index 509610864dee..420da7880c0d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -111,8 +111,12 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final boolean TRACE_CLEARING = Boolean.getBoolean("linux.native.menu.debug.trace.clearing"); private static final boolean TRACE_HIERARCHY_MISMATCHES = Boolean.getBoolean("linux.native.menu.debug.trace.hierarchy.mismatches"); private static final boolean SHOW_SWING_MENU = Boolean.getBoolean("linux.native.menu.debug.show.frame.menu"); + private static final boolean KDE_DISABLE_ROOT_MNEMONIC_PROCESSING = Boolean.getBoolean("linux.native.menu.kde.disable.root.mnemonic"); + private static final boolean SKIP_OPEN_MENU_COMMAND = Boolean.getBoolean("linux.native.menu.skip.open"); + private static final boolean FILL_MINIMALLY = Boolean.getBoolean("linux.native.menu.fill.minimally"); + private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); private static final GlobalMenuLib ourLib; private static final GlobalMenuLib.JLogger ourGLogger; @@ -299,8 +303,10 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { ApplicationManager.getApplication().assertIsDispatchThread(); + int[] stats = new int[]{0, 0, 0}; final int size = roots == null ? 0 : roots.size(); final List newRoots = new ArrayList<>(size); + if (roots != null) { for (ActionMenu am: roots) { final int uid = System.identityHashCode(am); @@ -308,6 +314,15 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { mi.jitem = am; mi.setLabelFromSwingPeer(am); newRoots.add(mi); + + if (!FILL_MINIMALLY) { + final long startMs = System.currentTimeMillis(); + am.removeAll(); + am.fillMenu(); + _syncChildren(mi, am, 1, stats); // NOTE: fill root menus to avoid empty submenu showing + final long elapsedMs = System.currentTimeMillis() - startMs; + if (TRACE_SYNC_STATS) _trace("filled root menu '%s', spent (in EDT) %d ms, stats: %s", String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); + } } } @@ -562,16 +577,24 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (TRACE_EVENTS) _trace("received event '%s' from item %s", _evtype2str(eventType), mi); - if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW || eventType == GlobalMenuLib.EVENT_CLOSED) { - final boolean check = myEventFilter.check(uid, eventType, mi); - if (!check) - return; + final boolean check = myEventFilter.check(uid, eventType, mi); + if (!check) + return; - if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) { + if ( + eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW + || (!SKIP_OPEN_MENU_COMMAND && eventType == GlobalMenuLib.EVENT_OPENED) + ) { // glib main-loop thread final long startMs = System.currentTimeMillis(); - int[] stats = new int[]{0, 0, 0}; + if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) + mi.lastAboutToShowMs = startMs; + + if (eventType == GlobalMenuLib.EVENT_OPENED && startMs - mi.lastAboutToShowMs < 2000) // simple protection to avoid double (frequent) filling + return; + + int[] stats = new int[]{0, 0, 0}; ApplicationManager.getApplication().invokeAndWait(()-> { // ETD-start final JMenuItem jmi = mi.jitem; @@ -587,7 +610,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final ActionMenu am = (ActionMenu)jmi; am.removeAll(); am.fillMenu(); - _syncChildren(mi, am, 1, stats); + _syncChildren(mi, am, FILL_MINIMALLY ? 1 : 2, stats); // NOTE: fill next submenus level to avoid empty submenu showing (intermittent) }); // glib main-loop thread @@ -595,12 +618,12 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (TRACE_SYNC_STATS) _trace("opened %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); _processChildren(mi); - } else { - // glib main-loop thread - // process GlobalMenuLib.EVENT_CLOSED - mi.scheduleClearSwing(); - } + } + if (eventType == GlobalMenuLib.EVENT_CLOSED) { + // glib main-loop thread + // process GlobalMenuLib.EVENT_CLOSED + mi.scheduleClearSwing(); return; } @@ -699,6 +722,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { Pointer nativePeer; int position = -1; + long lastAboutToShowMs = 0; long lastClosedMs = 0; Timer timerClearSwing; @@ -906,7 +930,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final long timeMs = System.currentTimeMillis(); if (eventType == GlobalMenuLib.EVENT_CLOSED) { mi.lastClosedMs = timeMs; - } else { + } else if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) { if (mi.rootPos == 0) { if (myTimer == null) { myLastFirstRootEventMs = timeMs; From d40667a77909baea242ee679994321da2e104ad3 Mon Sep 17 00:00:00 2001 From: Artem Bochkarev Date: Sun, 3 Feb 2019 20:07:38 +0300 Subject: [PATCH 110/138] linux-menu: fixed events filtering fixed: IDEA-204534 KDE global menu fixed: IDEA-201103 Linux native menu: some submenu are empty --- .../openapi/wm/impl/GlobalMenuLinux.java | 271 +++++++++++++----- 1 file changed, 202 insertions(+), 69 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index 420da7880c0d..bb71a35326fd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -108,6 +108,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final boolean TRACE_SYNC_STATS = Boolean.getBoolean("linux.native.menu.debug.trace.sync-stats"); private static final boolean TRACE_EVENTS = Boolean.getBoolean("linux.native.menu.debug.trace.events"); private static final boolean TRACE_EVENT_FILTER = Boolean.getBoolean("linux.native.menu.debug.trace.event-filter"); + private static final boolean TRACE_SKIPPED_EVENT = Boolean.getBoolean("linux.native.menu.debug.trace.skipped.event"); private static final boolean TRACE_CLEARING = Boolean.getBoolean("linux.native.menu.debug.trace.clearing"); private static final boolean TRACE_HIERARCHY_MISMATCHES = Boolean.getBoolean("linux.native.menu.debug.trace.hierarchy.mismatches"); private static final boolean SHOW_SWING_MENU = Boolean.getBoolean("linux.native.menu.debug.show.frame.menu"); @@ -115,7 +116,9 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final boolean KDE_DISABLE_ROOT_MNEMONIC_PROCESSING = Boolean.getBoolean("linux.native.menu.kde.disable.root.mnemonic"); private static final boolean SKIP_OPEN_MENU_COMMAND = Boolean.getBoolean("linux.native.menu.skip.open"); - private static final boolean FILL_MINIMALLY = Boolean.getBoolean("linux.native.menu.fill.minimally"); + private static final boolean DONT_FILL_ROOTS = SystemInfo.isKDE || Boolean.getBoolean("linux.native.dont.fill.roots"); + private static final boolean DONT_FILL_SUBMENU = Boolean.getBoolean("linux.native.menu.dont.fill.submenu"); + private static final boolean DISABLE_EVENTS_FILTERING = Boolean.getBoolean("linux.native.menu.disable.events.filtering"); private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); private static final GlobalMenuLib ourLib; @@ -133,6 +136,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private boolean myIsRootsUpdated = false; private boolean myIsEnabled = true; private boolean myIsDisposed = false; + private boolean myIsFirstFilling = true; // don't filter first packet of events (it causes slow reaction of KDE applet) private final GlobalMenuLib.JRunnable myOnWindowReleased; private final EventFilter myEventFilter = new EventFilter(); @@ -310,12 +314,12 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (roots != null) { for (ActionMenu am: roots) { final int uid = System.identityHashCode(am); - final MenuItemInternal mi = new MenuItemInternal(newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, am.getAnAction()); + final MenuItemInternal mi = new MenuItemInternal(null, newRoots.size(), uid, GlobalMenuLib.ITEM_SUBMENU, am.getAnAction()); mi.jitem = am; mi.setLabelFromSwingPeer(am); newRoots.add(mi); - if (!FILL_MINIMALLY) { + if (!DONT_FILL_ROOTS) { final long startMs = System.currentTimeMillis(); am.removeAll(); am.fillMenu(); @@ -446,20 +450,20 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } - private static MenuItemInternal _createInternalFromSwing(Component each) { + private static MenuItemInternal _createInternalFromSwing(MenuItemInternal parent, Component each) { if (each == null) return null; MenuItemInternal result = null; if (each instanceof ActionMenuItem) { final ActionMenuItem ami = (ActionMenuItem)each; - result = new MenuItemInternal(-1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getAnAction()); + result = new MenuItemInternal(parent, -1, System.identityHashCode(ami), ami.isToggleable() ? GlobalMenuLib.ITEM_CHECK : GlobalMenuLib.ITEM_SIMPLE, ami.getAnAction()); result.jitem = ami; } else if (each instanceof ActionMenu) { final ActionMenu am2 = (ActionMenu)each; - result = new MenuItemInternal(-1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getAnAction()); + result = new MenuItemInternal(parent, -1, System.identityHashCode(am2), GlobalMenuLib.ITEM_SUBMENU, am2.getAnAction()); result.jitem = am2; } else if (each instanceof JSeparator) { - result = new MenuItemInternal(-1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null); + result = new MenuItemInternal(parent, -1, System.identityHashCode(each), GlobalMenuLib.ITEM_SIMPLE, null); } else if (each instanceof StubItem) { // System.out.println("skip StubItem"); } else { @@ -492,7 +496,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { for (Component each : am.getPopupMenu().getComponents()) { MenuItemInternal cmi = mi.findCorrespondingChild(each); if (cmi == null) { - cmi = _createInternalFromSwing(each); + cmi = _createInternalFromSwing(mi, each); if (cmi != null) { cmi.position = itemPos++; mi.children.add(cmi); @@ -509,8 +513,12 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } if (cmi != null) { - if (deepness > 1 && (each instanceof ActionMenu)) - _syncChildren(cmi, (ActionMenu)each, deepness - 1, stats); + if (deepness > 1 && (each instanceof ActionMenu)) { + final ActionMenu jmiEach = (ActionMenu)each; + jmiEach.removeAll(); + jmiEach.fillMenu(); + _syncChildren(cmi, jmiEach, deepness - 1, stats); + } } } } @@ -558,8 +566,15 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { } } + private static boolean _isFillEvent(int eventType) { + return eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW || (!SKIP_OPEN_MENU_COMMAND && eventType == GlobalMenuLib.EVENT_OPENED); + } + @Override public void handleEvent(int uid, int eventType) { + _handleEvent(uid, eventType, true); + } + private void _handleEvent(int uid, int eventType, boolean doFiltering) { // glib main-loop thread final MenuItemInternal mi = _findMenuItem(uid); if (mi == null) { @@ -577,24 +592,27 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (TRACE_EVENTS) _trace("received event '%s' from item %s", _evtype2str(eventType), mi); - final boolean check = myEventFilter.check(uid, eventType, mi); - if (!check) + if (!DISABLE_EVENTS_FILTERING && !myIsFirstFilling && doFiltering && !myEventFilter.check(uid, eventType, mi)) return; - if ( - eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW - || (!SKIP_OPEN_MENU_COMMAND && eventType == GlobalMenuLib.EVENT_OPENED) - ) { + if (myIsFirstFilling) { + final Timer timer = new Timer(5000, e -> myIsFirstFilling = false); + timer.setRepeats(false); + timer.start(); + } + + if (_isFillEvent(eventType)) { // glib main-loop thread - final long startMs = System.currentTimeMillis(); + final long startMs = System.currentTimeMillis(); - if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) - mi.lastAboutToShowMs = startMs; + mi.cancelClearSwing(); - if (eventType == GlobalMenuLib.EVENT_OPENED && startMs - mi.lastAboutToShowMs < 2000) // simple protection to avoid double (frequent) filling - return; - - int[] stats = new int[]{0, 0, 0}; + // simple check to avoid double (or frequent) filling + final long timeMs = System.currentTimeMillis(); + int[] stats = new int[]{0, 0, 0}; + if (timeMs - mi.lastFilledMs < 1500 && mi.lastClearedMs < mi.lastFilledMs) { + if (TRACE_SKIPPED_EVENT) _trace("skipped fill-event for item '%s', use cached (too frequent fill-events)", String.valueOf(mi.txt)); + } else { ApplicationManager.getApplication().invokeAndWait(()-> { // ETD-start final JMenuItem jmi = mi.jitem; @@ -607,22 +625,24 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { return; } + mi.lastFilledMs = timeMs; + final ActionMenu am = (ActionMenu)jmi; am.removeAll(); am.fillMenu(); - _syncChildren(mi, am, FILL_MINIMALLY ? 1 : 2, stats); // NOTE: fill next submenus level to avoid empty submenu showing (intermittent) + _syncChildren(mi, am, DONT_FILL_SUBMENU ? 1 : 2, stats); // NOTE: fill next submenus level to avoid empty submenu showing (intermittent behaviour of menu-applet) }); // glib main-loop thread final long elapsedMs = System.currentTimeMillis() - startMs; - if (TRACE_SYNC_STATS) _trace("opened %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); + if (TRACE_SYNC_STATS) _trace("filled menu %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); _processChildren(mi); + } } if (eventType == GlobalMenuLib.EVENT_CLOSED) { // glib main-loop thread - // process GlobalMenuLib.EVENT_CLOSED mi.scheduleClearSwing(); return; } @@ -706,6 +726,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final int type; final AnAction action; + final MenuItemInternal parent; final List children = new ArrayList<>(); String txt; @@ -722,12 +743,13 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { Pointer nativePeer; int position = -1; - long lastAboutToShowMs = 0; - long lastClosedMs = 0; + long lastFilledMs = 0; + long lastClearedMs = 0; Timer timerClearSwing; - MenuItemInternal(int rootPos, int uid, int type, AnAction action) { + MenuItemInternal(MenuItemInternal parent, int rootPos, int uid, int type, AnAction action) { + this.parent = parent; this.rootPos = rootPos; this.uid = uid; this.type = type; @@ -890,15 +912,28 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { void scheduleClearSwing() { // exec at glib main-loop thread - if (timerClearSwing != null) - timerClearSwing.stop(); + if (timerClearSwing != null) { + timerClearSwing.restart(); + if (TRACE_CLEARING) _trace("\t reset clear timer of item '%s'", toStringShort()); + return; + } - timerClearSwing = new Timer(300, (e)->_clearSwing()); + timerClearSwing = new Timer(2000, (e)->_clearSwing()); timerClearSwing.setRepeats(false); timerClearSwing.start(); if (TRACE_CLEARING) _trace("\t scheduled (300 ms later) to clear '%s'", toStringShort()); } + void cancelClearSwing() { + // exec at glib main-loop thread + if (timerClearSwing != null) { + timerClearSwing.stop(); + timerClearSwing = null; + } + for (MenuItemInternal p = parent; p != null; p = p.parent) + p.cancelClearSwing(); + } + private void _clearSwing() { // exec at ETD if (timerClearSwing == null) @@ -916,59 +951,157 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { final ActionMenu am = (ActionMenu)jitem; am.clearItems(); clearChildrenSwingRefs(); + _onSwingCleared(System.currentTimeMillis()); if (TRACE_CLEARING) _trace("\t cleared '%s'", toStringShort()); } + + private void _onSwingCleared(long timeMs) { + lastClearedMs = timeMs; + if (timerClearSwing != null) { + timerClearSwing.stop(); + timerClearSwing = null; + } + + for (MenuItemInternal kid: children) + kid._onSwingCleared(timeMs); + } + } + + private static class QueuedEvent { + final int uid; + final int eventType; + final int rootId; + final long timeMs; + + private QueuedEvent(int uid, int eventType, int rootId, long timeMs) { + this.uid = uid; + this.eventType = eventType; + this.rootId = rootId; + this.timeMs = timeMs; + } + + static QueuedEvent of(int uid, int eventType, int rootId, long timeMs) { + return new QueuedEvent(uid, eventType, rootId, timeMs); + } } private class EventFilter { + final private ArrayList myQueued = new ArrayList<>(); private Timer myTimer; - private long myLastFirstRootEventMs = 0; + private long myClosedMs = 0; + @SuppressWarnings("unused") private GlobalMenuLib.JRunnable myGlibLoopRunnable; // holds runnable object - boolean check(int uid, int eventType, @NotNull MenuItemInternal mi) { - final long timeMs = System.currentTimeMillis(); - if (eventType == GlobalMenuLib.EVENT_CLOSED) { - mi.lastClosedMs = timeMs; - } else if (eventType == GlobalMenuLib.SIGNAL_ABOUT_TO_SHOW) { - if (mi.rootPos == 0) { - if (myTimer == null) { - myLastFirstRootEventMs = timeMs; - // start timer to call handleEvent(uid, eventType) after several ms - myTimer = new Timer(50, (e) -> { - if (myTimer == null) { - if (TRACE_EVENT_FILTER) _trace("EventFilter: skip delayed 'about-to-show' processing of first-root because timer was reset (i.e. myTimer == null)"); - return; - } - ourLib.execOnMainLoop(myGlibLoopRunnable = () -> handleEvent(uid, eventType)); - }); - myTimer.setRepeats(false); - myTimer.start(); - if (TRACE_EVENT_FILTER) _trace("EventFilter: start timer to process 'about-to-show' of first-root later"); - return false; + private boolean _isClosed() { return myClosedMs > 0; } + + private void _stopTimer() { + // exec at glib-main-thread + if (myTimer != null) + myTimer.stop(); + myTimer = null; + } + + private void _processQueue() { + // exec at glib-main-thread + for (QueuedEvent q: myQueued) + _handleEvent(q.uid, q.eventType, false); + myQueued.clear(); + } + + private void _startTimer() { + // exec at glib-main-thread + _stopTimer(); + + final Timer timer = new Timer(50, null); + timer.addActionListener((e) -> { + if (TRACE_EVENT_FILTER) _trace("EventFilter: start execution of timer callback"); // exec at EDT + if (myTimer != timer) {// check that timer wasn't reset + if (TRACE_EVENT_FILTER) _trace("EventFilter: skip timer-processing because timer was reset (i.e. myTimer == null)"); + return; + } + + ourLib.execOnMainLoop(myGlibLoopRunnable = () -> { + // remove continuous series of sequential root events + // because some of implementations (of menu applet) regularly send packets of root events ('about-to-show' or/and 'open') + final int lastRootId = myRoots.size() - 1; + int from = 0; + while (from < myQueued.size()) { + final int size = myQueued.size(); + + // 1. find event from second root + while (from < size && myQueued.get(from).rootId != 1) ++from; + if (from == size) break; + + // 2. rewind to first root + int first = from - 1; + if (first < 0 || myQueued.get(first).rootId != 0) { + // no events from first root, rewind forward + while (from < size && myQueued.get(from).rootId == 1) ++from; + continue; + } + while (first >= 1 && myQueued.get(first - 1).rootId == 0 && from - first <= 1) --first; + + // 3. find last root + int to = from + 1; + while (to < size && myQueued.get(to).rootId != lastRootId) ++to; + if (to == size) break; + while (to < size && myQueued.get(to).rootId == lastRootId) ++to; + + // 4. remove fake segment + if (TRACE_EVENT_FILTER) _trace("EventFilter: remove segment [%d, %d) from queue of size=%d", first, to, myQueued.size()); + myQueued.subList(first, to).clear(); + from = first + 1; } + if (!myQueued.isEmpty()) { + if (TRACE_ENABLED) _trace("EventFilter: process queued events, size=%d", myQueued.size()); + _processQueue(); + } else if (TRACE_ENABLED) _trace("EventFilter: queue is empty"); + myTimer = null; - } else if (mi.rootPos > 0) { - if ((timeMs - myLastFirstRootEventMs) < 50) { - if (TRACE_EVENT_FILTER) _trace("EventFilter: skip fake 'about-to-show' of root[%d]%s", mi.rootPos, myTimer != null ? " (reset timer)" : ""); - if (myTimer != null) { - myTimer.stop(); - myTimer = null; - } - return false; - } - if (TRACE_EVENT_FILTER) _trace("EventFilter: process real 'about-to-show' on root[%d]", mi.rootPos); + myClosedMs = 0; // open filter + if (TRACE_EVENT_FILTER) _trace("EventFilter: filter is opened"); + }); + }); + + myTimer = timer; + myTimer.setRepeats(false); + myTimer.start(); + if (TRACE_EVENT_FILTER) _trace("EventFilter: start timer"); + } + + boolean check(int uid, int eventType, @NotNull MenuItemInternal mi) { + // exec at glib-main-thread + final boolean isFillEvent = _isFillEvent(eventType); + final long timeMs = System.currentTimeMillis(); + + if (_isClosed()) { + if (timeMs - myClosedMs > 2000) { + // simple protection (open filter by timeout) + if (TRACE_ENABLED) _trace("EventFilter WARNING: close filter by timeout protection"); + _processQueue(); + _stopTimer(); + myClosedMs = 0; } else { - if (TRACE_EVENT_FILTER) _trace("EventFilter: process real 'about-to-show' on non-root item '%s'%s", mi.txt, myTimer != null ? " (reset timer)" : ""); - if (myTimer != null) { - myTimer.stop(); - myTimer = null; - } + // filter is closed + myQueued.add(QueuedEvent.of(uid, eventType, mi.rootPos, timeMs)); + if (myTimer != null) + myTimer.restart(); + return false; } } - return true; + // filter is opened + if (mi.rootPos != 0) + return true; + + // filter is opened and first root appeared + if (TRACE_EVENT_FILTER) _trace("EventFilter: close filter"); + myQueued.add(QueuedEvent.of(uid, eventType, mi.rootPos, timeMs)); + myClosedMs = timeMs; + _startTimer(); + return false; } } From 530b915230409f0f8296870d256e3a6b83173d2d Mon Sep 17 00:00:00 2001 From: Artem Bochkarev Date: Tue, 5 Feb 2019 00:08:07 +0300 Subject: [PATCH 111/138] linux-menu: fixed IDEA-201104 Linux native menu: popups are not closed when native menu is opened --- .../src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java index bb71a35326fd..0e36487a14ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/GlobalMenuLinux.java @@ -118,6 +118,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { private static final boolean SKIP_OPEN_MENU_COMMAND = Boolean.getBoolean("linux.native.menu.skip.open"); private static final boolean DONT_FILL_ROOTS = SystemInfo.isKDE || Boolean.getBoolean("linux.native.dont.fill.roots"); private static final boolean DONT_FILL_SUBMENU = Boolean.getBoolean("linux.native.menu.dont.fill.submenu"); + private static final boolean DONT_CLOSE_POPUPS = Boolean.getBoolean("linux.native.menu.dont.close.popups"); private static final boolean DISABLE_EVENTS_FILTERING = Boolean.getBoolean("linux.native.menu.disable.events.filtering"); private static final Logger LOG = Logger.getInstance(GlobalMenuLinux.class); @@ -603,8 +604,8 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { if (_isFillEvent(eventType)) { // glib main-loop thread - final long startMs = System.currentTimeMillis(); - + if (!DONT_CLOSE_POPUPS) + ApplicationManager.getApplication().invokeLater(() -> IdeEventQueue.getInstance().getPopupManager().closeAllPopups()); mi.cancelClearSwing(); // simple check to avoid double (or frequent) filling @@ -634,7 +635,7 @@ public class GlobalMenuLinux implements GlobalMenuLib.EventHandler, Disposable { }); // glib main-loop thread - final long elapsedMs = System.currentTimeMillis() - startMs; + final long elapsedMs = System.currentTimeMillis() - timeMs; if (TRACE_SYNC_STATS) _trace("filled menu %s '%s', spent (in EDT) %d ms, stats: %s", (mi.isRoot() ? "root menu" : "submenu"), String.valueOf(mi.txt), elapsedMs, _stats2str(stats)); _processChildren(mi); From f35507709df470b7a7c169c86abbbb0a6628c49d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Feb 2019 23:25:30 +0100 Subject: [PATCH 112/138] [vfs] more compact way of persisting symlink target attributes (IDEA-198269) --- .../openapi/vfs/newvfs/persistent/FSRecords.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index 4911e9cd9659..f009f9835ad5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -58,6 +58,7 @@ public class FSRecords { static final String VFS_FILES_EXTENSION = System.getProperty("idea.vfs.files.extension", ".dat"); private static final boolean ourStoreRootsSeparately = SystemProperties.getBooleanProperty("idea.store.roots.separately", false); + //TODO[anyone] when bumping the version, please delete `ourSymlinkTargetAttr_old` and use it's value for `ourSymlinkTargetAttr` private static final int VERSION = 22 + (weHaveContentHashes ? 0x10:0) + (IOUtil.ourByteBuffersUseNativeByteOrder ? 0x37:0) + 31 + (bulkAttrReadSupport ? 0x27:0) + (inlineAttributes ? 0x31 : 0) + (ourStoreRootsSeparately ? 0x63 : 0) + @@ -97,7 +98,8 @@ public class FSRecords { private static final int CORRUPTED_MAGIC = 0xabcf7f7f; private static final FileAttribute ourChildrenAttr = new FileAttribute("FsRecords.DIRECTORY_CHILDREN"); - private static final FileAttribute ourSymlinkTargetAttr = new FileAttribute("FsRecords.SYMLINK_TARGET"); + private static final FileAttribute ourSymlinkTargetAttr = new FileAttribute("FsRecords.SYMLINK_TARGET_2"); + private static final FileAttribute ourSymlinkTargetAttr_old = new FileAttribute("FsRecords.SYMLINK_TARGET"); private static final ReentrantReadWriteLock lock; private static final ReentrantReadWriteLock.ReadLock r; @@ -984,8 +986,12 @@ public class FSRecords { static @Nullable String readSymlinkTarget(int id) { return readAndHandleErrors(() -> { try (DataInputStream stream = readAttribute(id, ourSymlinkTargetAttr)) { - return stream != null ? StringUtil.nullize(stream.readUTF()) : null; + if (stream != null) return StringUtil.nullize(IOUtil.readUTF(stream)); } + try (DataInputStream stream = readAttribute(id, ourSymlinkTargetAttr_old)) { + if (stream != null) return StringUtil.nullize(stream.readUTF()); + } + return null; }); } @@ -993,7 +999,7 @@ public class FSRecords { writeAndHandleErrors(() -> { DbConnection.markDirty(); try (DataOutputStream stream = writeAttribute(id, ourSymlinkTargetAttr)) { - stream.writeUTF(StringUtil.notNullize(symlinkTarget)); + IOUtil.writeUTF(stream, StringUtil.notNullize(symlinkTarget)); } }); } From fa56d7afefa417384a3b7604acf08a084af25f29 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 5 Feb 2019 02:14:29 +0300 Subject: [PATCH 113/138] IDEA-206617 Cannot open Settings when a theme is applied --- .../options/colors/ColorAndFontOptions.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 2513341977fd..dc498134fe07 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -1,4 +1,4 @@ -// 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-2019 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.application.options.colors; @@ -34,6 +34,7 @@ import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.util.EventDispatcher; import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; @@ -510,9 +511,13 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract initScheme(schemeDelegate); mySchemes.put(schemeDelegate.getName(), schemeDelegate); } - - mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName()); - assert mySelectedScheme != null : EditorColorsManager.getInstance().getGlobalScheme().getName() + "; myschemes=" + mySchemes; + EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); + if (EditorColorsManagerImpl.isTempScheme(globalScheme)) { + mySelectedScheme = ContainerUtil.getFirstItem(mySchemes.values()); + } else { + mySelectedScheme = mySchemes.get(globalScheme.getName()); + } + assert mySelectedScheme != null : globalScheme.getName() + "; myschemes=" + mySchemes; } private static void initScheme(@NotNull MyColorScheme scheme) { From fb376a280178ed18bffca6f0247f9b02ea588295 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 4 Feb 2019 21:00:23 +0300 Subject: [PATCH 114/138] support volatile images --- .../openapi/wm/impl/IdeBackgroundUtil.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java index cc551e16e0d5..818b8b3d9335 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java @@ -57,6 +57,7 @@ import java.awt.geom.*; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; +import java.awt.image.VolatileImage; import java.net.URL; import java.util.Set; @@ -374,12 +375,14 @@ public class IdeBackgroundUtil { void runAllPainters(int x, int y, int width, int height, @Nullable Shape sourceShape, @Nullable Object reason) { if (width <= 1 || height <= 1) return; - // skip painters for transparent 'reasons' - if (reason instanceof Color && ((Color)reason).getAlpha() < 255) return; - if (reason instanceof Image) { - if (!(reason instanceof BufferedImage)) return; - if (((BufferedImage)reason).getColorModel().hasAlpha()) return; - } + boolean hasAlpha = + reason instanceof Color ? ((Color)reason).getAlpha() < 255 : + reason instanceof BufferedImage ? ((BufferedImage)reason).getColorModel().hasAlpha() : + reason instanceof VolatileImage ? ((VolatileImage)reason).getTransparency() != Transparency.OPAQUE : + true; + // skip painters when alpha is already present + if (hasAlpha) return; + Shape prevClip = getClip(); Shape tmpClip = calcTempClip(prevClip, sourceShape != null ? sourceShape : new Rectangle(x, y, width, height)); if (tmpClip == null) return; From 36dfa5cb13cdf23928a66659c99f24ecbf2f3876 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 5 Feb 2019 01:57:34 +0300 Subject: [PATCH 115/138] introduce NO_BACKGROUND to explicitly opt out --- .../src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java index 818b8b3d9335..935895791078 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeBackgroundUtil.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.AbstractPainter; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.StatusBar; import com.intellij.ui.EditorTextField; @@ -70,6 +71,8 @@ public class IdeBackgroundUtil { public static final String FRAME_PROP = "idea.background.frame"; public static final String TARGET_PROP = "idea.background.target"; + public static final Key NO_BACKGROUND = Key.create("SUPPRESS_BACKGROUND"); + public enum Fill { PLAIN, SCALE, TILE } @@ -403,6 +406,7 @@ public class IdeBackgroundUtil { private static class MyTransform implements PairFunction { @Override public Graphics2D fun(JComponent c, Graphics2D g) { + if (Boolean.TRUE.equals(UIUtil.getClientProperty(c, NO_BACKGROUND))) return g; String type = getComponentType(c); if (type == null) return g; if ("frame".equals(type)) return withFrameBackground(g, c); From fb570b42775046008425224ff03cb8f57341d392 Mon Sep 17 00:00:00 2001 From: Artemiy Sartakov Date: Tue, 5 Feb 2019 12:18:24 +0700 Subject: [PATCH 116/138] Javadoc: filter methods based on method signature and name only (IDEA-CR-42580) --- .../javaDoc/JavaDocReferenceInspection.java | 1 + .../codeInsight/javadoc/JavaDocUtil.java | 4 +-- .../javadoc/PsiDocMethodOrFieldRef.java | 34 +++++++++++-------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java index 66b5c92f0113..a203d62f35f5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspection.java @@ -69,6 +69,7 @@ public class JavaDocReferenceInspection extends LocalInspectionTool { boolean allAccessible = !REPORT_INACCESSIBLE || Arrays.stream(resolveResults).map(ResolveResult::getElement) + .filter(Objects::nonNull) .allMatch(element -> isAccessible(element, context)); return allAccessible ? null : diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java index 0489d403ed8a..03e93ade227a 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocUtil.java @@ -144,7 +144,7 @@ public class JavaDocUtil { } @Nullable - private static PsiElement findReferencedMember(PsiClass aClass, String memberRefText, PsiElement context) { + private static PsiElement findReferencedMember(@NotNull PsiClass aClass, @NotNull String memberRefText, PsiElement context) { int parenthIndex = memberRefText.indexOf('('); if (parenthIndex < 0) { String name = memberRefText; @@ -197,7 +197,7 @@ public class JavaDocUtil { allMethods = aClass.findMethodsByName(name, true); } - PsiMethod[] methods = PsiDocMethodOrFieldRef.findMethods(methodSignature, context, name, allMethods); + PsiMethod[] methods = PsiDocMethodOrFieldRef.findMethods(methodSignature, aClass, name, allMethods); if (methods.length == 0) return null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java index 562332543b8f..675d8ea011a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/PsiDocMethodOrFieldRef.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.resolve.JavaResolveUtil; @@ -44,9 +45,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; /** * @author mike @@ -204,26 +203,33 @@ public class PsiDocMethodOrFieldRef extends CompositePsiElement implements PsiDo @NotNull public static PsiMethod[] findMethods(@Nullable MethodSignature methodSignature, - @Nullable PsiElement scope, + @NotNull PsiClass scope, @Nullable String name, @NotNull PsiMethod[] allMethods) { - List methods = new ArrayList<>(); - List exactMethods = new ArrayList<>(); + final PsiClass superClass = scope.getSuperClass(); + final PsiSubstitutor substitutor = superClass == null ? PsiSubstitutor.EMPTY : + TypeConversionUtil.getSuperClassSubstitutor(superClass, scope, PsiSubstitutor.EMPTY); - for (PsiMethod method : allMethods) { - if (!method.getName().equals(name) || - methodSignature != null && - !MethodSignatureUtil.areSignaturesErasureEqual(methodSignature, method.getSignature(PsiSubstitutor.EMPTY))) { + final List candidates = new ArrayList<>(Arrays.asList(allMethods)); + final Set filteredMethods = new HashSet<>(); + + for (PsiMethod method : candidates) { + if (filteredMethods.contains(method)) { continue; } - if (scope == null || scope.equals(method.getContainingClass())) exactMethods.add(method); + if (!method.getName().equals(name) || + methodSignature != null && !MethodSignatureUtil.areSignaturesErasureEqual(method.getSignature(substitutor), methodSignature)) { + filteredMethods.add(method); + } - methods.add(method); + PsiSuperMethodImplUtil.getHierarchicalMethodSignature(method) + .getSuperSignatures() + .forEach(signature -> filteredMethods.add(signature.getMethod())); } - List found = exactMethods.size() == 1 ? exactMethods : methods; - return found.toArray(PsiMethod.EMPTY_ARRAY); + candidates.removeAll(filteredMethods); + return candidates.toArray(PsiMethod.EMPTY_ARRAY); } @NotNull From de56823187d1b436cda872e45f7d90381e5478b3 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Tue, 5 Feb 2019 09:19:48 +0300 Subject: [PATCH 117/138] OC-18271 move license info to community --- .../jetbrains/intellij/build/CommunityLibraryLicenses.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy index f66928c07f19..7d528091c55c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -102,6 +102,8 @@ class CommunityLibraryLicenses { additionalLibraryNames: ["asm-capture"]), new LibraryLicense(name: "ASM Tools", libraryName: "asm-tools", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html"), + new LibraryLicense(name: "AssertJ fluent assertions", libraryName: "assertJ", version: "3.11.1", license: "Apache 2.0", + url: "http://joel-costigliola.github.io/assertj/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt"), new LibraryLicense(name: "Automaton", libraryName: "automaton", version: "1.12-1", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php"), new LibraryLicense(name: "batik", libraryName: "batik", version: "1.9.1", license: "Apache 2.0", @@ -331,6 +333,8 @@ class CommunityLibraryLicenses { additionalLibraryNames: ["org.apache.maven.shared:maven-dependency-tree:1.2", "org.apache.maven.archetype:archetype-common:2.2"], version: "3.6.0", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0"), + new LibraryLicense(name: "Memory File System", libraryName: "memoryfilesystem", version: "1.3.0", license: "MIT", + url: "https://github.com/marschall/memoryfilesystem", licenseUrl: "http://opensource.org/licenses/MIT"), new LibraryLicense(name: "mercurial_prompthooks", attachedTo: "intellij.vcs.hg", version: "", license: "GPLv2 (used as hg extension called from hg executable)", url: "https://github.com/willemv/mercurial_prompthooks", From 1b87c1a508a47baa67c8645022f470126cc3f861 Mon Sep 17 00:00:00 2001 From: Artemiy Sartakov Date: Tue, 5 Feb 2019 13:24:49 +0700 Subject: [PATCH 118/138] ConvertToLocalInspection: changed quick-fix to explicitly show type of code block where field is used (IDEA-CR-42222) --- .../FieldCanBeLocalInspection.java | 31 ++++++++++++------- .../afterBlocksInSameMethod.java | 2 +- .../convert2Local/afterFinalFieldIsCopy.java | 2 +- .../convert2Local/afterInitializer.java | 2 +- .../convert2Local/afterMultipleMethods.java | 2 +- .../afterSetterAfterSuperConstructorCall.java | 2 +- .../beforeBlocksInSameMethod.java | 2 +- .../convert2Local/beforeFinalFieldIsCopy.java | 2 +- .../convert2Local/beforeInitializer.java | 2 +- .../convert2Local/beforeMultipleMethods.java | 2 +- .../beforeMultipleMethodsOnReadOnly.java | 2 +- ...beforeSetterAfterSuperConstructorCall.java | 2 +- .../convert2Local/beforeUsedInJavadoc.java | 2 +- .../src/messages/InspectionsBundle.properties | 3 +- 14 files changed, 33 insertions(+), 25 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index acbf7bece84c..d5c54e5ed308 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -38,7 +38,6 @@ import javax.swing.*; import java.awt.*; import java.util.List; import java.util.*; -import java.util.stream.Collectors; public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTool { @NonNls public static final String SHORT_NAME = "FieldCanBeLocal"; @@ -376,22 +375,30 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix { private final String myName; - private ConvertFieldToLocalQuickFix(Map> refs) { - Set methods = refs.keySet().stream() - .filter(block -> block.getParent() instanceof PsiMethod) - .map(block -> (PsiMethod)block.getParent()) - .collect(Collectors.toSet()); + private ConvertFieldToLocalQuickFix(@NotNull Map> refs) { + final Set blocks = refs.keySet(); + final PsiElement block; + if (blocks.size() == 1) { + block = + PsiTreeUtil.getNonStrictParentOfType(blocks.toArray(PsiCodeBlock.EMPTY_ARRAY)[0], PsiClassInitializer.class, PsiMethod.class); + } + else { + block = null; + } - myName = determineName(methods, refs); + myName = determineName(block); } @NotNull - private String determineName(Set methods, Map> refs) { - if (methods.isEmpty() || methods.size() != refs.size()) return getFamilyName(); - if (methods.size() > 1) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.multiple.methods", methods.size()); + private String determineName(@Nullable PsiElement block) { + if (block instanceof PsiClassInitializer) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.initializer"); - final String methodName = methods.toArray(PsiMethod.EMPTY_ARRAY)[0].getName(); - return InspectionsBundle.message("inspection.field.can.be.local.quickfix.one.method", methodName); + if (block instanceof PsiMethod) { + if (((PsiMethod)block).isConstructor()) return InspectionsBundle.message("inspection.field.can.be.local.quickfix.constructor"); + return InspectionsBundle.message("inspection.field.can.be.local.quickfix.one.method", ((PsiMethod)block).getName()); + } + + return getFamilyName(); } @NotNull diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java index e28339b72fb9..702f28feefe3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterBlocksInSameMethod.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'IntelliJBugConvertToLocal'" "true" +// "Convert field to local variable in constructor" "true" import java.util.ArrayList; class ITest { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java index ee74b9147a99..0405c3e3036f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'Test'" "true" +// "Convert field to local variable in constructor" "true" class Test { public Test(String param) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java index 742386daff93..1f581d88f2f6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterInitializer.java @@ -1,4 +1,4 @@ -// "Convert to local" "true" +// "Convert field to local variable in initializer section" "true" class TestInitializer { { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java index 3400ab952148..8a6d7b1f7802 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java @@ -1,4 +1,4 @@ -// "Convert field to local variables in 2 methods" "true" +// "Convert to local" "true" class Test { int getFoo1() { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java index c586623db745..ef019fc8a502 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterSetterAfterSuperConstructorCall.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'FieldCanBeLocalTest'" "true" +// "Convert field to local variable in constructor" "true" import javax.swing.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java index 36b9906265ce..b6bfe18e30e9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeBlocksInSameMethod.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'IntelliJBugConvertToLocal'" "true" +// "Convert field to local variable in constructor" "true" import java.util.ArrayList; class ITest { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java index 6bf2affe92ba..063b1808fc58 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'Test'" "true" +// "Convert field to local variable in constructor" "true" class Test { private final String field; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java index 6cb02e618645..15ae086ba8cf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeInitializer.java @@ -1,4 +1,4 @@ -// "Convert to local" "true" +// "Convert field to local variable in initializer section" "true" class TestInitializer { private boolean field; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java index 8966a4769718..aefb1a497eee 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java @@ -1,4 +1,4 @@ -// "Convert field to local variables in 2 methods" "true" +// "Convert to local" "true" class Test { private int myFoo; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java index db61483db9ad..509aa695768e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethodsOnReadOnly.java @@ -1,4 +1,4 @@ -// "Convert to local" "false" +// "Fix all 'Field can be local' problems in file" "false" class MyClassTest { private boolean editable = false; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java index 46cce76e3c23..49741a03cca9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeSetterAfterSuperConstructorCall.java @@ -1,4 +1,4 @@ -// "Convert field to local variable in method 'FieldCanBeLocalTest'" "true" +// "Convert field to local variable in constructor" "true" import javax.swing.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java index 65e8b00ac9d9..dbd56d5024bb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeUsedInJavadoc.java @@ -1,4 +1,4 @@ -// "Convert to local" "false" +// "Fix all 'Field can be local' problems in file" "false" class TestFieldConversion { private static int someInt = 0; diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index e5c5c55fca39..8d242127784f 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -196,7 +196,8 @@ inspection.field.can.be.local.problem.descriptor=Field can be converted to a loc inspection.parameter.can.be.local.display.name=Parameter can be local inspection.parameter.can.be.local.problem.descriptor=Parameter can be converted to a local variable inspection.convert.to.local.quickfix=Convert to local -inspection.field.can.be.local.quickfix.multiple.methods=Convert field to local variables in {0} methods +inspection.field.can.be.local.quickfix.initializer=Convert field to local variable in initializer section +inspection.field.can.be.local.quickfix.constructor=Convert field to local variable in constructor inspection.field.can.be.local.quickfix.one.method=Convert field to local variable in method ''{0}'' inspection.unused.return.value.display.name=Method can be void From 0db6222faf228eb156ae047a028c77b477995b53 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 5 Feb 2019 07:44:09 +0100 Subject: [PATCH 119/138] make names more consistent --- .../extensions/impl/ExtensionPointImpl.java | 58 ++++++++++--------- .../impl/InterfaceExtensionPoint.java | 2 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java index 1ad0c1f282f8..9693bab18773 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.java @@ -41,12 +41,18 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { protected final ExtensionsAreaImpl myOwner; private final PluginDescriptor myDescriptor; - @NotNull protected Set myExtensionAdapters = Collections.emptySet(); // guarded by this + // guarded by this + @NotNull + protected Set myAdapters = Collections.emptySet(); + + @NotNull + // guarded by this + private List myLoadedAdapters = Collections.emptyList(); + @SuppressWarnings("unchecked") @NotNull - private ExtensionPointListener[] myEPListeners = ExtensionPointListener.EMPTY_ARRAY; // guarded by this - @NotNull - private List myLoadedAdapters = Collections.emptyList(); // guarded by this + // guarded by this + private ExtensionPointListener[] myListeners = ExtensionPointListener.EMPTY_ARRAY; @Nullable protected Class myExtensionClass; @@ -143,7 +149,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } private void notifyListenersOnAdd(@NotNull T extension, @Nullable PluginDescriptor pluginDescriptor) { - for (ExtensionPointListener listener : myEPListeners) { + for (ExtensionPointListener listener : myListeners) { try { listener.extensionAdded(extension, pluginDescriptor); } @@ -200,7 +206,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { return !cache.isEmpty(); } synchronized (this) { - return myExtensionAdapters.size() + myLoadedAdapters.size() > 0; + return myAdapters.size() + myLoadedAdapters.size() > 0; } } @@ -210,7 +216,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { if (processingAdaptersNow) { throw new IllegalStateException("Recursive processAdapters() detected. You must have called 'getExtensions()' from within your extension constructor - don't. Either pass extension via constructor parameter or call getExtensions() later."); } - int totalSize = myExtensionAdapters.size() + myLoadedAdapters.size(); + int totalSize = myAdapters.size() + myLoadedAdapters.size(); Class extensionClass = getExtensionClass(); @SuppressWarnings("unchecked") T[] result = (T[])Array.newInstance(extensionClass, totalSize); @@ -221,11 +227,11 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { processingAdaptersNow = true; try { ExtensionComponentAdapter[] adapters = new ExtensionComponentAdapter[totalSize]; - myExtensionAdapters.toArray(adapters); - ArrayUtil.copy(myLoadedAdapters, adapters, myExtensionAdapters.size()); + myAdapters.toArray(adapters); + ArrayUtil.copy(myLoadedAdapters, adapters, myAdapters.size()); LoadingOrder.sort(adapters); - myExtensionAdapters = new LinkedHashSet<>(adapters.length); - ContainerUtil.addAll(myExtensionAdapters, adapters); + myAdapters = new LinkedHashSet<>(adapters.length); + ContainerUtil.addAll(myAdapters, adapters); Set loaded = ContainerUtil.newHashOrEmptySet(myLoadedAdapters); OpenTHashSet duplicates = new OpenTHashSet<>(adapters.length); @@ -263,9 +269,9 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { catch (Exception e) { LOG.error(e); } - myExtensionAdapters.remove(adapter); + myAdapters.remove(adapter); } - myExtensionAdapters = Collections.emptySet(); + myAdapters = Collections.emptySet(); if (extensionIndex != result.length) { result = Arrays.copyOf(result, extensionIndex); @@ -279,7 +285,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { // used in upsource public synchronized void removeUnloadableExtensions() { - ExtensionComponentAdapter[] adapters = myExtensionAdapters.toArray(ExtensionComponentAdapter.EMPTY_ARRAY); + ExtensionComponentAdapter[] adapters = myAdapters.toArray(ExtensionComponentAdapter.EMPTY_ARRAY); for (ExtensionComponentAdapter adapter : adapters) { try { adapter.getComponentImplementation(); @@ -322,7 +328,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @Override public synchronized void unregisterExtension(@NotNull Class extensionClass) { - for (ExtensionComponentAdapter adapter : ContainerUtil.concat(myExtensionAdapters, myLoadedAdapters)) { + for (ExtensionComponentAdapter adapter : ContainerUtil.concat(myAdapters, myLoadedAdapters)) { if (adapter.getAssignableToClassName().equals(extensionClass.getCanonicalName())) { unregisterExtensionAdapter(adapter); return; @@ -352,7 +358,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } private void notifyListenersOnRemove(@NotNull T extensionObject, PluginDescriptor pluginDescriptor) { - for (ExtensionPointListener listener : myEPListeners) { + for (ExtensionPointListener listener : myListeners) { try { listener.extensionRemoved(extensionObject, pluginDescriptor); } @@ -384,15 +390,15 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { // true if added private boolean addListener(@NotNull ExtensionPointListener listener) { - if (ArrayUtil.indexOf(myEPListeners, listener) != -1) return false; + if (ArrayUtil.indexOf(myListeners, listener) != -1) return false; //noinspection unchecked - myEPListeners = ArrayUtil.append(myEPListeners, listener, n->n==0?ExtensionPointListener.EMPTY_ARRAY:new ExtensionPointListener[n]); + myListeners = ArrayUtil.append(myListeners, listener, n-> n == 0 ? ExtensionPointListener.EMPTY_ARRAY : new ExtensionPointListener[n]); return true; } private boolean removeListener(@NotNull ExtensionPointListener listener) { - if (ArrayUtil.indexOf(myEPListeners, listener) == -1) return false; + if (ArrayUtil.indexOf(myListeners, listener) == -1) return false; //noinspection unchecked - myEPListeners = ArrayUtil.remove(myEPListeners, listener, n->n==0?ExtensionPointListener.EMPTY_ARRAY:new ExtensionPointListener[n]); + myListeners = ArrayUtil.remove(myListeners, listener, n-> n == 0 ? ExtensionPointListener.EMPTY_ARRAY : new ExtensionPointListener[n]); return true; } @@ -435,7 +441,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @Override public synchronized void reset() { - myExtensionAdapters = Collections.emptySet(); + myAdapters = Collections.emptySet(); for (T extension : getExtensionList()) { unregisterExtension(extension); } @@ -468,10 +474,10 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { } synchronized void registerExtensionAdapter(@NotNull ExtensionComponentAdapter adapter) { - if (myExtensionAdapters == Collections.emptySet()) { - myExtensionAdapters = new LinkedHashSet<>(); + if (myAdapters == Collections.emptySet()) { + myAdapters = new LinkedHashSet<>(); } - myExtensionAdapters.add(adapter); + myAdapters.add(adapter); clearCache(); } @@ -482,7 +488,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { private void unregisterExtensionAdapter(@NotNull ExtensionComponentAdapter adapter) { try { - if (!myExtensionAdapters.isEmpty() && myExtensionAdapters.remove(adapter)) { + if (!myAdapters.isEmpty() && myAdapters.remove(adapter)) { return; } @@ -532,7 +538,7 @@ public abstract class ExtensionPointImpl implements ExtensionPoint { @TestOnly final synchronized void notifyAreaReplaced(@NotNull ExtensionsArea oldArea) { - for (final ExtensionPointListener listener : myEPListeners) { + for (final ExtensionPointListener listener : myListeners) { if (listener instanceof ExtensionPointAndAreaListener) { ((ExtensionPointAndAreaListener)listener).areaReplaced(oldArea); } diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java index 1113b3925358..c2bf41f3733f 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.java @@ -32,7 +32,7 @@ public final class InterfaceExtensionPoint extends ExtensionPointImpl { @Override public synchronized void reset() { - for (Object extensionAdapter : myExtensionAdapters) { + for (Object extensionAdapter : myAdapters) { myOwner.getPicoContainer().unregisterComponent(((ComponentAdapter)extensionAdapter).getComponentKey()); } super.reset(); From 26c261955a1bf0c0e9c7dbc324b16894a9bcde29 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Feb 2019 07:55:37 +0100 Subject: [PATCH 120/138] don't mark Throwable.getCause as nullable it results in many false positives where specific exceptions (e.g. InvocationTargetException) actually have it non-null --- java/jdkAnnotations/java/lang/annotations.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/java/jdkAnnotations/java/lang/annotations.xml b/java/jdkAnnotations/java/lang/annotations.xml index 601cb43aa126..85221f3da3f0 100644 --- a/java/jdkAnnotations/java/lang/annotations.xml +++ b/java/jdkAnnotations/java/lang/annotations.xml @@ -816,8 +816,5 @@ - - - From 0aab4871850a61ddb2dbce531424f91f725839dc Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Feb 2019 08:03:39 +0100 Subject: [PATCH 121/138] disallow index access during root change events because indexable file set might be inconsistent at this moment, and a query would anyway lead to expensive synchronous VFS walk --- .../intellij/openapi/project/NoAccessDuringPsiEvents.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java b/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java index b96aed725ee2..f492fb74479f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/NoAccessDuringPsiEvents.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.project; +import com.intellij.ProjectTopics; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -44,6 +45,8 @@ public class NoAccessDuringPsiEvents { if (!application.isWriteAccessAllowed()) return false; MessageBus bus = application.getMessageBus(); - return bus.hasUndeliveredEvents(VirtualFileManager.VFS_CHANGES) || bus.hasUndeliveredEvents(PsiModificationTracker.TOPIC); + return bus.hasUndeliveredEvents(VirtualFileManager.VFS_CHANGES) || + bus.hasUndeliveredEvents(PsiModificationTracker.TOPIC) || + bus.hasUndeliveredEvents(ProjectTopics.PROJECT_ROOTS); } } From ade3083464e3f8844c8e8e794a8844eceb68893a Mon Sep 17 00:00:00 2001 From: "alexey.afanasiev" Date: Tue, 5 Feb 2019 11:08:33 +0300 Subject: [PATCH 122/138] [groovy] IDEA-202693 Lambda fix parsing parenthesized expressions and priorities --- .../lang/parser/GroovyGeneratedParser.java | 309 +++++++++--------- .../plugins/groovy/lang/parser/groovy.bnf | 37 +-- .../plugins/groovy/lang/parser/parserUtils.kt | 8 +- .../lang/parser/ExpressionsParsingTest.groovy | 14 + .../lang/resolve/ResolveLocalTest.groovy | 4 +- .../groovy/expressions/lambda/assign5.test | 28 ++ .../groovy/expressions/lambda/assign6.test | 26 ++ .../expressions/lambda/implicitReturn1.test | 17 +- .../expressions/lambda/methodCall13.test | 26 ++ .../expressions/lambda/methodCall14.test | 29 ++ .../expressions/lambda/methodCall15.test | 22 ++ .../expressions/lambda/methodCall16.test | 24 ++ .../expressions/lambda/methodCall17.test | 30 ++ .../expressions/lambda/nestedLambda.test | 19 +- .../groovy/expressions/lambda/return1.test | 19 +- .../expressions/lambda/standalone1.test | 17 +- .../expressions/lambda/standalone2.test | 27 +- 17 files changed, 440 insertions(+), 216 deletions(-) create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test diff --git a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java index 4fe123a99773..7c8ab02b7327 100644 --- a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java +++ b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java @@ -175,9 +175,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { else if (t == LAMBDA_BLOCK) { r = lambda_block(b, 0); } - else if (t == LAMBDA_EXPRESSION) { - r = lambda_expression(b, 0); - } else if (t == LEFT_SHIFT_SIGN) { r = left_shift_sign(b, 0); } @@ -968,40 +965,39 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // spread_list_argument | named_argument | lambda_argument | expression (map_argument_label map_argument)? + // spread_list_argument | named_argument | expression (map_argument_label map_argument)? static boolean argument(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "argument")) return false; boolean r; Marker m = enter_section_(b); r = spread_list_argument(b, l + 1); if (!r) r = named_argument(b, l + 1); - if (!r) r = lambda_argument(b, l + 1); - if (!r) r = argument_3(b, l + 1); + if (!r) r = argument_2(b, l + 1); exit_section_(b, m, null, r); return r; } // expression (map_argument_label map_argument)? - private static boolean argument_3(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3")) return false; + private static boolean argument_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2")) return false; boolean r; Marker m = enter_section_(b); r = expression(b, l + 1, -1); - r = r && argument_3_1(b, l + 1); + r = r && argument_2_1(b, l + 1); exit_section_(b, m, null, r); return r; } // (map_argument_label map_argument)? - private static boolean argument_3_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3_1")) return false; - argument_3_1_0(b, l + 1); + private static boolean argument_2_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2_1")) return false; + argument_2_1_0(b, l + 1); return true; } // map_argument_label map_argument - private static boolean argument_3_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "argument_3_1_0")) return false; + private static boolean argument_2_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument_2_1_0")) return false; boolean r; Marker m = enter_section_(b); r = map_argument_label(b, l + 1); @@ -1370,14 +1366,14 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // (<> mb_nl) enhanced_expression_or_application + // (<> mb_nl) expression_or_application static boolean assignment_expression_rvalue(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "assignment_expression_rvalue")) return false; boolean r, p; Marker m = enter_section_(b, l, _NONE_); r = assignment_expression_rvalue_0(b, l + 1); p = r; // pin = 1 - r = r && enhanced_expression_or_application(b, l + 1); + r = r && expression_or_application(b, l + 1); exit_section_(b, l, m, r, p, null); return r || p; } @@ -3268,16 +3264,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return true; } - /* ********************************************************** */ - // lambda_expression | expression_or_application - static boolean enhanced_expression_or_application(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "enhanced_expression_or_application")) return false; - boolean r; - r = lambda_expression(b, l + 1); - if (!r) r = expression_or_application(b, l + 1); - return r; - } - /* ********************************************************** */ // '{' mb_nl enum_members '}' public static boolean enum_body(PsiBuilder b, int l) { @@ -4313,28 +4299,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - /* ********************************************************** */ - // !<> lambda_expression - static boolean lambda_argument(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_argument")) return false; - boolean r; - Marker m = enter_section_(b); - r = lambda_argument_0(b, l + 1); - r = r && lambda_expression(b, l + 1); - exit_section_(b, m, null, r); - return r; - } - - // !<> - private static boolean lambda_argument_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_argument_0")) return false; - boolean r; - Marker m = enter_section_(b, l, _NOT_); - r = !isApplicationArguments(b, l + 1); - exit_section_(b, l, m, r, false, null); - return r; - } - /* ********************************************************** */ // '{' mb_nl block_levels '}' public static boolean lambda_block(PsiBuilder b, int l) { @@ -4383,22 +4347,11 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - /* ********************************************************** */ - // lambda_expression_base | clear_variants_and_fail - public static boolean lambda_expression(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_expression")) return false; - boolean r; - Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); - r = lambda_expression_base(b, l + 1); - if (!r) r = clear_variants_and_fail(b, l + 1); - exit_section_(b, l, m, r, false, null); - return r; - } - /* ********************************************************** */ // lambda_expression_head mb_nl lambda_body static boolean lambda_expression_base(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_expression_base")) return false; + if (!nextTokenIs(b, T_LPAREN)) return false; boolean r, p; Marker m = enter_section_(b, l, _NONE_); r = lambda_expression_head(b, l + 1); @@ -4413,6 +4366,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { // lambda_parameter_list mb_nl '->' static boolean lambda_expression_head(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_expression_head")) return false; + if (!nextTokenIsFast(b, T_LPAREN)) return false; boolean r; Marker m = enter_section_(b); r = lambda_parameter_list(b, l + 1); @@ -4436,12 +4390,38 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // parenthesized_lambda_parameter_list | single_lambda_parameter_list - static boolean lambda_parameter_list(PsiBuilder b, int l) { + // empty_parens | '(' <> ')' + public static boolean lambda_parameter_list(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_parameter_list")) return false; + if (!nextTokenIs(b, T_LPAREN)) return false; boolean r; - r = parenthesized_lambda_parameter_list(b, l + 1); - if (!r) r = single_lambda_parameter_list(b, l + 1); + Marker m = enter_section_(b); + r = empty_parens(b, l + 1); + if (!r) r = lambda_parameter_list_1(b, l + 1); + exit_section_(b, m, PARAMETER_LIST, r); + return r; + } + + // '(' <> ')' + private static boolean lambda_parameter_list_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_parameter_list_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, T_LPAREN); + r = r && comma_list(b, l + 1, GroovyGeneratedParser::lambda_parameter_list_1_1_0); + r = r && consumeToken(b, T_RPAREN); + exit_section_(b, m, null, r); + return r; + } + + // mb_nl lambda_parameter + private static boolean lambda_parameter_list_1_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_parameter_list_1_1_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = mb_nl(b, l + 1); + r = r && lambda_parameter(b, l + 1); + exit_section_(b, m, null, r); return r; } @@ -4557,14 +4537,14 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // ['=' mb_nl enhanced_expression_or_application] + // ['=' mb_nl expression_or_application] static boolean mb_initializer(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "mb_initializer")) return false; mb_initializer_0(b, l + 1); return true; } - // '=' mb_nl enhanced_expression_or_application + // '=' mb_nl expression_or_application private static boolean mb_initializer_0(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "mb_initializer_0")) return false; boolean r, p; @@ -4572,7 +4552,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { r = consumeTokenFast(b, T_ASSIGN); p = r; // pin = 1 r = r && report_error_(b, mb_nl(b, l + 1)); - r = p && enhanced_expression_or_application(b, l + 1) && r; + r = p && expression_or_application(b, l + 1) && r; exit_section_(b, l, m, r, p, null); return r || p; } @@ -5586,71 +5566,6 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r || p; } - /* ********************************************************** */ - // parenthesized_lambda_expression_head mb_nl lambda_body - static boolean parenthesized_lambda_expression_base(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression_base")) return false; - if (!nextTokenIs(b, T_LPAREN)) return false; - boolean r, p; - Marker m = enter_section_(b, l, _NONE_); - r = parenthesized_lambda_expression_head(b, l + 1); - p = r; // pin = 1 - r = r && report_error_(b, mb_nl(b, l + 1)); - r = p && lambda_body(b, l + 1) && r; - exit_section_(b, l, m, r, p, null); - return r || p; - } - - /* ********************************************************** */ - // parenthesized_lambda_parameter_list mb_nl '->' - static boolean parenthesized_lambda_expression_head(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression_head")) return false; - if (!nextTokenIsFast(b, T_LPAREN)) return false; - boolean r; - Marker m = enter_section_(b); - r = parenthesized_lambda_parameter_list(b, l + 1); - r = r && mb_nl(b, l + 1); - r = r && consumeToken(b, T_ARROW); - exit_section_(b, m, null, r); - return r; - } - - /* ********************************************************** */ - // empty_parens | '(' <> ')' - public static boolean parenthesized_lambda_parameter_list(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list")) return false; - if (!nextTokenIs(b, T_LPAREN)) return false; - boolean r; - Marker m = enter_section_(b); - r = empty_parens(b, l + 1); - if (!r) r = parenthesized_lambda_parameter_list_1(b, l + 1); - exit_section_(b, m, PARAMETER_LIST, r); - return r; - } - - // '(' <> ')' - private static boolean parenthesized_lambda_parameter_list_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list_1")) return false; - boolean r; - Marker m = enter_section_(b); - r = consumeToken(b, T_LPAREN); - r = r && comma_list(b, l + 1, GroovyGeneratedParser::parenthesized_lambda_parameter_list_1_1_0); - r = r && consumeToken(b, T_RPAREN); - exit_section_(b, m, null, r); - return r; - } - - // mb_nl lambda_parameter - private static boolean parenthesized_lambda_parameter_list_1_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_parameter_list_1_1_0")) return false; - boolean r; - Marker m = enter_section_(b); - r = mb_nl(b, l + 1); - r = r && lambda_parameter(b, l + 1); - exit_section_(b, m, null, r); - return r; - } - /* ********************************************************** */ // <> // | <> @@ -6136,11 +6051,85 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // modifier_list IDENTIFIER - public static boolean single_lambda_parameter(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "single_lambda_parameter")) return false; + // <> expression_or_application + // | expression_or_application !<> + // | lazy_lambda_block + static boolean single_argument_lambda_body(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); + Marker m = enter_section_(b); + r = single_argument_lambda_body_0(b, l + 1); + if (!r) r = single_argument_lambda_body_1(b, l + 1); + if (!r) r = lazy_lambda_block(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // <> expression_or_application + private static boolean single_argument_lambda_body_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = isParameterizedClosure(b, l + 1); + r = r && expression_or_application(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // expression_or_application !<> + private static boolean single_argument_lambda_body_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = expression_or_application(b, l + 1); + r = r && single_argument_lambda_body_1_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // !<> + private static boolean single_argument_lambda_body_1_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_body_1_1")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !isParsedAsClosure(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + /* ********************************************************** */ + // single_argument_lambda_expression_head mb_nl single_argument_lambda_body + static boolean single_argument_lambda_expression_base(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression_base")) return false; + boolean r, p; + Marker m = enter_section_(b, l, _NONE_); + r = single_argument_lambda_expression_head(b, l + 1); + p = r; // pin = 1 + r = r && report_error_(b, mb_nl(b, l + 1)); + r = p && single_argument_lambda_body(b, l + 1) && r; + exit_section_(b, l, m, r, p, null); + return r || p; + } + + /* ********************************************************** */ + // single_argument_lambda_parameter_list mb_nl '->' + static boolean single_argument_lambda_expression_head(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression_head")) return false; + boolean r; + Marker m = enter_section_(b); + r = single_argument_lambda_parameter_list(b, l + 1); + r = r && mb_nl(b, l + 1); + r = r && consumeToken(b, T_ARROW); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // modifier_list IDENTIFIER + public static boolean single_argument_lambda_parameter(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); r = modifier_list(b, l + 1); r = r && consumeToken(b, IDENTIFIER); exit_section_(b, l, m, r, false, null); @@ -6148,12 +6137,23 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // single_lambda_parameter - public static boolean single_lambda_parameter_list(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "single_lambda_parameter_list")) return false; + // !<> single_argument_lambda_parameter + public static boolean single_argument_lambda_parameter_list(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter_list")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER_LIST, ""); - r = single_lambda_parameter(b, l + 1); + Marker m = enter_section_(b, l, _NONE_, PARAMETER_LIST, ""); + r = single_argument_lambda_parameter_list_0(b, l + 1); + r = r && single_argument_lambda_parameter(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // !<> + private static boolean single_argument_lambda_parameter_list_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_parameter_list_0")) return false; + boolean r; + Marker m = enter_section_(b, l, _NOT_); + r = !isApplicationArguments(b, l + 1); exit_section_(b, l, m, r, false, null); return r; } @@ -7513,7 +7513,8 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { // 14: PREFIX(not_expression) ATOM(cast_expression) // 15: POSTFIX(index_expression) POSTFIX(safe_index_expression) POSTFIX(postfix_unary_expression) // 16: POSTFIX(method_reference_expression) POSTFIX(attribute_expression) POSTFIX(qualified_reference_expression) POSTFIX(property_expression) - // 17: POSTFIX(method_call_expression) ATOM(lazy_closure) ATOM(parenthesized_lambda_expression) ATOM(list_or_map) + // 17: POSTFIX(method_call_expression) ATOM(lazy_closure) ATOM(lambda_expression) ATOM(single_argument_lambda_expression) + // ATOM(list_or_map) // 18: ATOM(new_anonymous_expression) ATOM(new_expression) // 19: ATOM(unqualified_reference_expression) ATOM(built_in_type_expression) ATOM(literal) ATOM(gstring) // ATOM(regex) ATOM(parenthesized_expression) @@ -7527,7 +7528,8 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { if (!r) r = not_expression(b, l + 1); if (!r) r = cast_expression(b, l + 1); if (!r) r = lazy_closure(b, l + 1); - if (!r) r = parenthesized_lambda_expression(b, l + 1); + if (!r) r = lambda_expression(b, l + 1); + if (!r) r = single_argument_lambda_expression(b, l + 1); if (!r) r = list_or_map(b, l + 1); if (!r) r = new_anonymous_expression(b, l + 1); if (!r) r = new_expression(b, l + 1); @@ -8203,12 +8205,23 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // parenthesized_lambda_expression_base | clear_variants_and_fail - public static boolean parenthesized_lambda_expression(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "parenthesized_lambda_expression")) return false; + // lambda_expression_base | clear_variants_and_fail + public static boolean lambda_expression(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "lambda_expression")) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); - r = parenthesized_lambda_expression_base(b, l + 1); + Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); + r = lambda_expression_base(b, l + 1); + if (!r) r = clear_variants_and_fail(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + // single_argument_lambda_expression_base | clear_variants_and_fail + public static boolean single_argument_lambda_expression(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "single_argument_lambda_expression")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, LAMBDA_EXPRESSION, ""); + r = single_argument_lambda_expression_base(b, l + 1); if (!r) r = clear_variants_and_fail(b, l + 1); exit_section_(b, l, m, r, false, null); return r; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf index d4b4db0f9983..b3a8c5432290 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf @@ -938,32 +938,29 @@ array_declaration ::= mandatory_expression optional_expression* { consumeTokenMe private mandatory_expression ::= '[' expression ']' { pin = 1 consumeTokenMethod = 'consumeTokenFast' } private optional_expression ::= '[' expression? ']' { pin = 1 consumeTokenMethod = 'consumeTokenFast' } -private priority1_2 ::= method_call_expression | lazy_closure | parenthesized_lambda_expression | list_or_map +private priority1_2 ::= method_call_expression | lazy_closure | lambda_expression | single_argument_lambda_expression | list_or_map constructor_call_expression ::= &('this' | 'super') unqualified_reference_expression call_tail method_call_expression ::= expression call_tail private call_tail ::= call_argument_list (mb_nl lazy_closure)* | empty_argument_list <> -lambda_expression ::= lambda_expression_base | clear_variants_and_fail +lambda_expression ::= lambda_expression_base | clear_variants_and_fail private lambda_expression_base ::= lambda_expression_head mb_nl lambda_body { pin = 1 } private lambda_expression_head ::= lambda_parameter_list mb_nl '->' { consumeTokenMethod = 'consumeTokenFast' } -private lambda_parameter_list ::= parenthesized_lambda_parameter_list | single_lambda_parameter_list - -parenthesized_lambda_expression ::= parenthesized_lambda_expression_base | clear_variants_and_fail { elementType = lambda_expression } -private parenthesized_lambda_expression_base ::= parenthesized_lambda_expression_head mb_nl lambda_body { pin = 1 } -private parenthesized_lambda_expression_head ::= parenthesized_lambda_parameter_list mb_nl '->' -{ - consumeTokenMethod = 'consumeTokenFast' -} - -parenthesized_lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } +lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } lambda_parameter ::= modifier_list mb_type_element var { elementType = parameter } +private lambda_body ::= (!<> lazy_lambda_block) | expression_or_application -single_lambda_parameter_list ::= single_lambda_parameter { elementType = parameter_list } -single_lambda_parameter ::= modifier_list IDENTIFIER { +single_argument_lambda_expression::= single_argument_lambda_expression_base | clear_variants_and_fail { elementType = lambda_expression } +private single_argument_lambda_expression_base ::= single_argument_lambda_expression_head mb_nl single_argument_lambda_body { pin = 1 } +private single_argument_lambda_expression_head ::= single_argument_lambda_parameter_list mb_nl '->' { consumeTokenMethod = 'consumeTokenFast' } + +single_argument_lambda_parameter_list ::= !<> single_argument_lambda_parameter { elementType = parameter_list } +single_argument_lambda_parameter ::= modifier_list IDENTIFIER { elementType = parameter } - -private lambda_body ::= (!<> lazy_lambda_block) | expression_or_application +private single_argument_lambda_body ::= <> expression_or_application + | expression_or_application !<> + | lazy_lambda_block lazy_lambda_block ::= <> { elementType = lambda_block @@ -1103,7 +1100,7 @@ elvis_expression ::= expression mb_nl ('?:' mb_nl) expression private priority15 ::= assignment_expression | tuple_assignment_expression assignment_expression ::= expression assignment_expression_rvalue { rightAssociative = true } -private assignment_expression_rvalue ::= (<> mb_nl) enhanced_expression_or_application { pin = 1 } +private assignment_expression_rvalue ::= (<> mb_nl) expression_or_application { pin = 1 } tuple_assignment_expression ::= single_tuple_assignment | multi_tuple_assignment private single_tuple_assignment ::= single_tuple tuple_initializer // don't pin because "(foo)" may be a parenthesized expression @@ -1120,7 +1117,6 @@ tuple ::= '(' unqualified_reference_expression (',' unqualified_reference_expres // region Applications expression_or_application ::= <> { elementType = '' name = '' } -private enhanced_expression_or_application ::= lambda_expression | expression_or_application private expression_or_application_inner ::= expression application* private application ::= no_nl <> { @@ -1168,9 +1164,8 @@ application_argument_list ::= <> private application_arguments ::= argument (',' mb_nl argument)* private parse_argument ::= <> -private argument ::= spread_list_argument | named_argument | lambda_argument | expression (map_argument_label map_argument)? +private argument ::= spread_list_argument | named_argument | expression (map_argument_label map_argument)? -private lambda_argument ::= !<> lambda_expression left map_argument_label ::= &':' { elementType = argument_label @@ -1257,7 +1252,7 @@ left doc_reference_tail ::= '.' code_reference_part { elementType = code_referen // region Variables private var ::= IDENTIFIER mb_initializer -private mb_initializer ::= ['=' mb_nl enhanced_expression_or_application] +private mb_initializer ::= ['=' mb_nl expression_or_application] { pin('.*') = 1 consumeTokenMethod = 'consumeTokenFast' diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt index 932ae83f164d..117743b69048 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parserUtils.kt @@ -18,7 +18,7 @@ import com.intellij.psi.tree.TokenSet import org.jetbrains.plugins.groovy.GroovyBundle import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.closure_header_with_arrow -import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.parenthesized_lambda_expression_head +import org.jetbrains.plugins.groovy.lang.parser.GroovyGeneratedParser.lambda_expression_head import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes.* import org.jetbrains.plugins.groovy.lang.psi.GroovyTokenSets.* import org.jetbrains.plugins.groovy.util.get @@ -417,6 +417,10 @@ private fun castOperandCheckInner(builder: PsiBuilder): Boolean { return false } +fun isParsedAsClosure(builder: PsiBuilder, level: Int): Boolean { + return builder.latestDoneMarker?.tokenType == CLOSURE +} + fun isParameterizedClosure(builder: PsiBuilder, level: Int): Boolean { return builder.lookahead { isParameterizedClosureInner(this, level) @@ -431,7 +435,7 @@ private fun isParameterizedClosureInner(builder: PsiBuilder, level: Int): Boolea fun isParameterizedLambda(builder: PsiBuilder, level: Int): Boolean { return builder.lookahead { - parenthesized_lambda_expression_head(builder, level) + lambda_expression_head(builder, level) } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 3c372e044886..6b07909bbde3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -794,6 +794,10 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testlambda$assign4() { doTest() } + void testlambda$assign5() { doTest() } + + void testlambda$assign6() { doTest() } + void testlambda$methodCall1() { doTest() } void testlambda$methodCall2() { doTest() } @@ -818,6 +822,16 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testlambda$methodCall12() { doTest() } + void testlambda$methodCall13() { doTest() } + + void testlambda$methodCall14() { doTest() } + + void testlambda$methodCall15() { doTest() } + + void testlambda$methodCall16() { doTest() } + + void testlambda$methodCall17() { doTest() } + void testlambda$command1() { doTest() } void testlambda$command2() { doTest() } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy index e268592f0805..81e6fb16ac9b 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveLocalTest.groovy @@ -116,8 +116,8 @@ class ResolveLocalTest implements ResolveTest { void 'variable after lambda'() { resolveTest 'def l = a -> a; a ', null resolveTest 'def l = (a) -> a; a ', null - resolveTest 'def l = (Integer a) -> {} a ', null - resolveTest 'def l = a -> {} a ', null + resolveTest 'def l = (Integer a) -> {}; a ', null + resolveTest 'def l = a -> {}; a ', null } @Test diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test new file mode 100644 index 000000000000..e72914d4265f --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign5.test @@ -0,0 +1,28 @@ +def l = ((a) -> a) +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('l') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test new file mode 100644 index 000000000000..bbff28f11932 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign6.test @@ -0,0 +1,26 @@ +def l = (a -> a) +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('l') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test index 12b4c6d6ed89..69ea5beddccc 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/implicitReturn1.test @@ -17,13 +17,16 @@ Groovy script Open block PsiElement({)('{') PsiWhiteSpace('\n ') - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') PsiElement(new line)('\n') PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test new file mode 100644 index 000000000000..4ca9a50490ef --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall13.test @@ -0,0 +1,26 @@ +m(() -> {} as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Safe cast expression + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test new file mode 100644 index 000000000000..1d2d411f0de3 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall14.test @@ -0,0 +1,29 @@ +m((() -> {}) as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Safe cast expression + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test new file mode 100644 index 000000000000..cb070621bbd2 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall15.test @@ -0,0 +1,22 @@ +m((() -> {})) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test new file mode 100644 index 000000000000..fb9fb7feb67f --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall16.test @@ -0,0 +1,24 @@ +m((a -> {})) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Parenthesized expression + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') + PsiElement())(')') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test new file mode 100644 index 000000000000..4546184f6467 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/methodCall17.test @@ -0,0 +1,30 @@ +m(a -> {} as Foo) +----- +Groovy script + Method call + Reference expression + PsiElement(identifier)('m') + Arguments + PsiElement(()('(') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Safe cast expression + Closable block + PsiElement({)('{') + Parameter list + + PsiElement(})('}') + PsiWhiteSpace(' ') + PsiElement(as)('as') + PsiWhiteSpace(' ') + Type element + Reference element + PsiElement(identifier)('Foo') + PsiElement())(')') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test index 9432a630aa4e..ce484d47ef6c 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/nestedLambda.test @@ -19,11 +19,14 @@ Groovy script PsiWhiteSpace(' ') PsiElement(->)('->') PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('b') - PsiWhiteSpace(' ') - PsiErrorElement:',' expected, got '->' - PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('b') \ No newline at end of file + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('b') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('b') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test index be22a273f657..a43670396055 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/return1.test @@ -20,13 +20,16 @@ Groovy script RETURN statement PsiElement(return)('return') PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected - PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') PsiElement(new line)('\n') PsiElement(})('}') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test index 4284f8bb28ee..cd762db3d2da 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone1.test @@ -1,11 +1,14 @@ a -> a ----- Groovy script - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected + Lambda expression + Parameter list + Parameter + Modifiers + + PsiElement(identifier)('a') + PsiWhiteSpace(' ') PsiElement(->)('->') - PsiWhiteSpace(' ') - Reference expression - PsiElement(identifier)('a') \ No newline at end of file + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test index 4de12019daf3..ddd4a76eebac 100644 --- a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/standalone2.test @@ -1,18 +1,19 @@ a -> { a } ----- Groovy script - Reference expression - PsiElement(identifier)('a') - PsiWhiteSpace(' ') - PsiErrorElement:'->' unexpected - PsiElement(->)('->') - PsiWhiteSpace(' ') - Closable block - PsiElement({)('{') - PsiWhiteSpace(' ') + Lambda expression Parameter list - - Reference expression - PsiElement(identifier)('a') + Parameter + Modifiers + + PsiElement(identifier)('a') PsiWhiteSpace(' ') - PsiElement(})('}') \ No newline at end of file + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiWhiteSpace(' ') + Reference expression + PsiElement(identifier)('a') + PsiWhiteSpace(' ') + PsiElement(})('}') \ No newline at end of file From 17f71838910b3ab6d4d1321fda893f18eb314fd1 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 5 Feb 2019 09:00:50 +0100 Subject: [PATCH 123/138] avoid NPE if test fails and no project --- .../fixtures/impl/LightIdeaTestFixtureImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java index ff0c2e169944..004e3d9824ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightIdeaTestFixtureImpl.java @@ -1,4 +1,4 @@ -// 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-2019 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.testFramework.fixtures.impl; @@ -57,7 +57,11 @@ public class LightIdeaTestFixtureImpl extends BaseFixture implements LightIdeaTe myCodeStyleSettingsTracker.checkForSettingsDamage(); } }) - .append(() -> PlatformTestCase.waitForProjectLeakingThreads(project, 10, TimeUnit.SECONDS)) + .append(() -> { + if (project != null) { + PlatformTestCase.waitForProjectLeakingThreads(project, 10, TimeUnit.SECONDS); + } + }) .append(() -> super.tearDown()) // call all disposables' dispose() while the project is still open .append(() -> { if (project != null) { From 4f8d652a9492fa73c3fd915836c36fa9bd5aec33 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Tue, 5 Feb 2019 10:37:08 +0300 Subject: [PATCH 124/138] Gradle: do not rebuild the whole module for CompileFileAction --- .../java/src/execution/build/GradleProjectTaskRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java b/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java index 51b463983d84..8e1c48f893c4 100644 --- a/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java +++ b/plugins/gradle/java/src/execution/build/GradleProjectTaskRunner.java @@ -266,7 +266,7 @@ public class GradleProjectTaskRunner extends ProjectTaskRunner { Collection buildRootTasks = buildTasksMap.getModifiable(rootProjectPath); final String moduleType = getExternalModuleType(module); - if (!moduleBuildTask.isIncrementalBuild()) { + if (!moduleBuildTask.isIncrementalBuild() && !(moduleBuildTask instanceof ModuleFilesBuildTask)) { projectInitScripts.add(String.format(FORCE_COMPILE_TASKS_INIT_SCRIPT_TEMPLATE, gradlePath)); } String assembleTask = "assemble"; From c955be737ead760f52cdee74807125790fcc6e34 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Tue, 5 Feb 2019 11:38:17 +0300 Subject: [PATCH 125/138] record "navigation.goto.declaration" in GotoDeclarationOnlyHandler It turns out that FeatureUsageTracker is used for Productivity Guide, so we gotta record this feature usage. The feature is recorded in GotoDeclarationOnlyHandler only so it doesn't matter through what action (GotoDeclaration or GotoDeclarationOnly) the user invokes it. --- .../navigation/actions/GotoDeclarationOnlyHandler.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt index 065dd3b87a75..326d060aaa57 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationOnlyHandler.kt @@ -7,6 +7,7 @@ import com.intellij.codeInsight.TargetElementUtil import com.intellij.codeInsight.hint.HintManager import com.intellij.codeInsight.navigation.NavigationUtil import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.* +import com.intellij.featureStatistics.FeatureUsageTracker import com.intellij.ide.util.DefaultPsiElementCellRenderer import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.DumbService @@ -22,6 +23,8 @@ object GotoDeclarationOnlyHandler : CodeInsightActionHandler { override fun startInWriteAction(): Boolean = false override fun invoke(project: Project, editor: Editor, file: PsiFile) { + FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration") + val dumbService = DumbService.getInstance(project) try { dumbService.isAlternativeResolveEnabled = true From e825df9b5c3e2f85e84f1a5df60bb5330d0fd0b7 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 5 Feb 2019 11:03:06 +0700 Subject: [PATCH 126/138] DFA: report imprecise methods in tests --- .../codeInspection/dataFlow/DataFlowInspectionBase.java | 4 +++- .../inspection/dataFlow/fixture/ComplexInitializer.java | 4 ++-- .../dataFlow/fixture/EqualsInLoopNotTooComplex.java | 2 +- .../inspection/dataFlow/fixture/ManyObjectEquals.java | 2 +- .../inspection/dataFlow/fixture/NestedScopeComplexity.java | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index cdf5517de5f3..6b8560f9ceaa 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -13,6 +13,7 @@ import com.intellij.codeInspection.dataFlow.fix.*; import com.intellij.codeInspection.dataFlow.instructions.*; import com.intellij.codeInspection.dataFlow.value.DfaConstValue; import com.intellij.codeInspection.nullable.NullableStuffInspectionBase; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -195,7 +196,8 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(); final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates); if (rc == RunnerResult.OK) { - if (dfaRunner.wasForciblyMerged() && Registry.is("ide.dfa.report.imprecise")) { + if (dfaRunner.wasForciblyMerged() && + (ApplicationManager.getApplication().isUnitTestMode() || Registry.is("ide.dfa.report.imprecise"))) { reportAnalysisQualityProblem(holder, scope, "dataflow.not.precise"); } createDescription(dfaRunner, holder, visitor, scope); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java index c1857d1f5da1..4ad7c38c282e 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComplexInitializer.java @@ -63,7 +63,7 @@ class Constants { static native Object get(); } -class NotTooComplexInitializer { +class NotTooComplexInitializer { static { int i = 1; for(Object obj = Constants.get(); obj != Constants.C5; obj = Constants.get()) { @@ -84,7 +84,7 @@ class NotTooComplexInitializer { } } } -class NotTooComplexMergingInitializer { +class NotTooComplexMergingInitializer { static { foo(Constants.C1 == null, Constants.C2 == null, Constants.C3 == null, Constants.C4 == null, Constants.C5 == null, Constants.C6 == null, diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java b/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java index 6ed439c2022b..7f3c1421df40 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/EqualsInLoopNotTooComplex.java @@ -4,7 +4,7 @@ class Test { enum A {X, Y, Z}; List list1, list2; - void test(List tokens) { + void test(List tokens) { String t = "int"; A s = A.X; A l = A.X; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java b/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java index f55d980c445e..e43e3d23c7f7 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ManyObjectEquals.java @@ -191,7 +191,7 @@ public class ManyObjectEquals { private String test183; @Override - public boolean equals(Object o) { + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ManyObjectEquals test = (ManyObjectEquals) o; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java b/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java index 4bef90d1228d..f56cf68892a9 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/NestedScopeComplexity.java @@ -30,7 +30,7 @@ class NestedScopeComplexity { static Object get() {return new Object();} - void test() { + void test() { int i = 1; for(Object obj = get(); obj != C100; obj = get()) { if (obj == C1) i = 2; From d472470240bf89de868357fa25482e0f17a81b14 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 5 Feb 2019 16:10:18 +0700 Subject: [PATCH 127/138] ExceptionWorker: check if lineNumber is positive (EA-135836 - IOOBE: LineSet.checkLineIndex) --- .../src/com/intellij/execution/filters/ExceptionWorker.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java index 77c0502b04a7..3c7716208b16 100644 --- a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java +++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java @@ -127,7 +127,8 @@ public class ExceptionWorker { else { virtualFiles = virtualFilesInContent; } - ToIntFunction columnFinder = elementMatcher == null ? null : new ExceptionColumnFinder(elementMatcher, myInfo.lineNumber - 1); + ToIntFunction columnFinder = + elementMatcher == null || myInfo.lineNumber < 0 ? null : new ExceptionColumnFinder(elementMatcher, myInfo.lineNumber - 1); HyperlinkInfo linkInfo = HyperlinkInfoFactory.getInstance().createMultipleFilesHyperlinkInfo(virtualFiles, myInfo.lineNumber - 1, myProject, columnFinder); Filter.Result result = new Filter.Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes); From df691937fe04c253fc68ffad7162be71be0a448d Mon Sep 17 00:00:00 2001 From: "alexey.afanasiev" Date: Tue, 5 Feb 2019 12:02:34 +0300 Subject: [PATCH 128/138] [groovy] IDEA-202693 Fix parsing varargs in lambda expressions --- .../lang/parser/GroovyGeneratedParser.java | 21 +--- .../plugins/groovy/lang/parser/groovy.bnf | 3 +- .../lang/parser/ExpressionsParsingTest.groovy | 2 + .../groovy/expressions/lambda/assign7.test | 108 ++++++++++++++++++ 4 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test diff --git a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java index 7c8ab02b7327..5e88c2edad25 100644 --- a/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java +++ b/plugins/groovy/groovy-psi/gen/org/jetbrains/plugins/groovy/lang/parser/GroovyGeneratedParser.java @@ -4377,20 +4377,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // modifier_list mb_type_element var - public static boolean lambda_parameter(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "lambda_parameter")) return false; - boolean r; - Marker m = enter_section_(b, l, _NONE_, PARAMETER, ""); - r = modifier_list(b, l + 1); - r = r && mb_type_element(b, l + 1); - r = r && var(b, l + 1); - exit_section_(b, l, m, r, false, null); - return r; - } - - /* ********************************************************** */ - // empty_parens | '(' <> ')' + // empty_parens | '(' <> ')' public static boolean lambda_parameter_list(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_parameter_list")) return false; if (!nextTokenIs(b, T_LPAREN)) return false; @@ -4402,7 +4389,7 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // '(' <> ')' + // '(' <> ')' private static boolean lambda_parameter_list_1(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_parameter_list_1")) return false; boolean r; @@ -4414,13 +4401,13 @@ public class GroovyGeneratedParser implements PsiParser, LightPsiParser { return r; } - // mb_nl lambda_parameter + // mb_nl parse_parameter private static boolean lambda_parameter_list_1_1_0(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "lambda_parameter_list_1_1_0")) return false; boolean r; Marker m = enter_section_(b); r = mb_nl(b, l + 1); - r = r && lambda_parameter(b, l + 1); + r = r && parse_parameter(b, l + 1); exit_section_(b, m, null, r); return r; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf index b3a8c5432290..9a6bd2a022d3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/groovy.bnf @@ -946,8 +946,7 @@ private call_tail ::= call_argument_list (mb_nl lazy_closure)* | empty_argument_ lambda_expression ::= lambda_expression_base | clear_variants_and_fail private lambda_expression_base ::= lambda_expression_head mb_nl lambda_body { pin = 1 } private lambda_expression_head ::= lambda_parameter_list mb_nl '->' { consumeTokenMethod = 'consumeTokenFast' } -lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } -lambda_parameter ::= modifier_list mb_type_element var { elementType = parameter } +lambda_parameter_list ::= empty_parens | '(' <> ')' { elementType = parameter_list } private lambda_body ::= (!<> lazy_lambda_block) | expression_or_application single_argument_lambda_expression::= single_argument_lambda_expression_base | clear_variants_and_fail { elementType = lambda_expression } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy index 6b07909bbde3..3b686c9777ea 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy @@ -798,6 +798,8 @@ class ExpressionsParsingTest extends GroovyParsingTestCase { void testlambda$assign6() { doTest() } + void testlambda$assign7() { doTest() } + void testlambda$methodCall1() { doTest() } void testlambda$methodCall2() { doTest() } diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test new file mode 100644 index 000000000000..86b8e2e80100 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/expressions/lambda/assign7.test @@ -0,0 +1,108 @@ +def bar = (String a, Date b = null, int i = -1, String c, String d = 'd', String e, String ... f) -> {} +----- +Groovy script + Variable definitions + Modifiers + PsiElement(def)('def') + PsiWhiteSpace(' ') + Variable + PsiElement(identifier)('bar') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Lambda expression + Parameter list + PsiElement(()('(') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('a') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('Date') + PsiWhiteSpace(' ') + PsiElement(identifier)('b') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Literal + PsiElement(null)('null') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Built in type + PsiElement(int)('int') + PsiWhiteSpace(' ') + PsiElement(identifier)('i') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Unary expression + PsiElement(-)('-') + Literal + PsiElement(Integer)('1') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('c') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('d') + PsiWhiteSpace(' ') + PsiElement(=)('=') + PsiWhiteSpace(' ') + Literal + PsiElement(single quoted string)(''d'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(identifier)('e') + PsiElement(,)(',') + PsiWhiteSpace(' ') + Parameter + Modifiers + + Type element + Reference element + PsiElement(identifier)('String') + PsiWhiteSpace(' ') + PsiElement(...)('...') + PsiWhiteSpace(' ') + PsiElement(identifier)('f') + PsiElement())(')') + PsiWhiteSpace(' ') + PsiElement(->)('->') + PsiWhiteSpace(' ') + Lambda body block + PsiElement({)('{') + PsiElement(})('}') \ No newline at end of file From 84337e01685093a91998c58ffc0c74b2c71de394 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Feb 2019 10:12:02 +0100 Subject: [PATCH 129/138] CachedValue javadoc: add a note on result equivalence --- .../src/com/intellij/psi/util/CachedValue.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValue.java b/platform/core-api/src/com/intellij/psi/util/CachedValue.java index 5e20a88c892d..4972cea4a0f4 100644 --- a/platform/core-api/src/com/intellij/psi/util/CachedValue.java +++ b/platform/core-api/src/com/intellij/psi/util/CachedValue.java @@ -15,8 +15,8 @@ */ package com.intellij.psi.util; -import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.Getter; +import com.intellij.openapi.util.RecursionGuard; import org.jetbrains.annotations.NotNull; /** @@ -37,7 +37,18 @@ import org.jetbrains.annotations.NotNull; * be run concurrently on more than one thread. Due to this and unpredictable garbage collection, * cached value providers shouldn't have side effects.

* - * Important note: if you store the CachedValue in a field or user data of some object {@code X}, then its {@link CachedValueProvider} + * Result equivalence: CachedValue might return a different result even if the previous one + * is still reachable and not garbage-collected, and dependencies haven't changed. Therefore CachedValue results + * should be equivalent and interchangeable if they're called multiple times. Examples: + *
    + *
  • If PSI declarations are cached, {@link #equals} or at least {@link com.intellij.psi.PsiManager#areElementsEquivalent} + * should hold for results from the same CachedValue.
  • + *
  • {@link com.intellij.psi.ResolveResult} objects should have equivalent {@code getElement()} values.
  • + *
  • Cached arrays or lists should have the same number of elements, and they also should be equivalent and come in the same order.
  • + *
  • If the result object's class has a meaningful {@link #equals} method, it should hold.
  • + *
+ * + * Context-independence: if you store the CachedValue in a field or user data of some object {@code X}, then its {@link CachedValueProvider} * may only depend on X and parts of global system state that don't change while {@code X} is alive and valid (e.g. application/project components/services). * Otherwise re-invoking the CachedValueProvider after invalidation would use outdated data and produce incorrect results, * possibly causing exceptions in places far, far away. In particular, the provider may not capture: From bbb15eb971feac3003798618a400288db286d9c4 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 9 Jan 2019 20:12:07 +0300 Subject: [PATCH 130/138] IDEA-87811 vcs: support line status markers for "modified without checkout" files --- .../vcs/impl/VcsFileStatusProvider.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java index 34c689c0cfb2..03b665ba888d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java @@ -148,11 +148,22 @@ public class VcsFileStatusProvider implements FileStatusProvider, VcsBaseContent VcsBaseContentProvider provider = findProviderFor(file); return provider == null ? null : provider.getBaseRevision(file); } - final Change change = ChangeListManager.getInstance(myProject).getChange(file); - if (change == null) return null; - final ContentRevision beforeRevision = change.getBeforeRevision(); - if (beforeRevision == null) return null; - return new BaseContentImpl(beforeRevision); + + ChangeListManager changeListManager = ChangeListManager.getInstance(myProject); + + Change change = changeListManager.getChange(file); + if (change != null) { + ContentRevision beforeRevision = change.getBeforeRevision(); + return beforeRevision == null ? null : new BaseContentImpl(beforeRevision); + } + + FileStatus status = changeListManager.getStatus(file); + if (status == FileStatus.HIJACKED) { + VcsCurrentRevisionProxy beforeRevision = VcsCurrentRevisionProxy.create(file, myProject); + return beforeRevision == null ? null : new BaseContentImpl(beforeRevision); + } + + return null; } @Nullable From 81a997ae8db7fe24be038519981cf57239b65de3 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 17 Jan 2019 14:51:41 +0300 Subject: [PATCH 131/138] IDEA-87811 vcs: do not load revision content if it's not needed VcsCurrentRevisionProxy.getRevisionNumber loads revision content, that might be not necessary in BaseContent. --- .../vcs/impl/VcsFileStatusProvider.java | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java index 03b665ba888d..dbc7f1bd35da 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsFileStatusProvider.java @@ -23,6 +23,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.diff.DiffProvider; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl; import com.intellij.openapi.vcs.rollback.RollbackEnvironment; @@ -159,8 +160,12 @@ public class VcsFileStatusProvider implements FileStatusProvider, VcsBaseContent FileStatus status = changeListManager.getStatus(file); if (status == FileStatus.HIJACKED) { - VcsCurrentRevisionProxy beforeRevision = VcsCurrentRevisionProxy.create(file, myProject); - return beforeRevision == null ? null : new BaseContentImpl(beforeRevision); + AbstractVcs vcs = ProjectLevelVcsManager.getInstance(myProject).getVcsFor(file); + DiffProvider diffProvider = vcs != null ? vcs.getDiffProvider() : null; + if (diffProvider != null) { + VcsRevisionNumber currentRevision = diffProvider.getCurrentRevision(file); + return currentRevision == null ? null : new HijackedBaseContent(diffProvider, file, currentRevision); + } } return null; @@ -199,26 +204,59 @@ public class VcsFileStatusProvider implements FileStatusProvider, VcsBaseContent @Nullable @Override public String loadContent() { - try { - if (myContentRevision instanceof ByteBackedContentRevision) { - byte[] revisionContent = ((ByteBackedContentRevision)myContentRevision).getContentAsBytes(); - FilePath filePath = myContentRevision.getFile(); + return loadContentRevision(myContentRevision); + } + } - if (revisionContent != null) { - Charset charset = DiffContentFactoryImpl.guessCharset(revisionContent, filePath); - return CharsetToolkit.decodeString(revisionContent, charset); - } - else { - return null; - } + private static class HijackedBaseContent implements BaseContent { + @NotNull private final DiffProvider myDiffProvider; + @NotNull private final VirtualFile myFile; + @NotNull private final VcsRevisionNumber myRevision; + + HijackedBaseContent(@NotNull DiffProvider diffProvider, + @NotNull VirtualFile file, + @NotNull VcsRevisionNumber revision) { + myDiffProvider = diffProvider; + myFile = file; + myRevision = revision; + } + + @NotNull + @Override + public VcsRevisionNumber getRevisionNumber() { + return myRevision; + } + + @Nullable + @Override + public String loadContent() { + ContentRevision contentRevision = myDiffProvider.createFileContent(myRevision, myFile); + if (contentRevision == null) return null; + return loadContentRevision(contentRevision); + } + } + + @Nullable + private static String loadContentRevision(@NotNull ContentRevision contentRevision) { + try { + if (contentRevision instanceof ByteBackedContentRevision) { + byte[] revisionContent = ((ByteBackedContentRevision)contentRevision).getContentAsBytes(); + FilePath filePath = contentRevision.getFile(); + + if (revisionContent != null) { + Charset charset = DiffContentFactoryImpl.guessCharset(revisionContent, filePath); + return CharsetToolkit.decodeString(revisionContent, charset); } else { - return myContentRevision.getContent(); + return null; } } - catch (VcsException ex) { - return null; + else { + return contentRevision.getContent(); } } + catch (VcsException ex) { + return null; + } } } From 308b261327efe3ea020ae8047403c0d35c77763f Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 5 Feb 2019 12:30:26 +0300 Subject: [PATCH 132/138] deprecate ArtifactIncrementalCompilerContext class which isn't used by the build infrastructure anymore --- .../elements/ArtifactIncrementalCompilerContext.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java b/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java index 6ee65f524f8d..00e3a951d024 100644 --- a/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java +++ b/java/compiler/openapi/src/com/intellij/packaging/elements/ArtifactIncrementalCompilerContext.java @@ -15,8 +15,12 @@ */ package com.intellij.packaging.elements; +import org.jetbrains.annotations.ApiStatus; + /** - * @author nik + * @deprecated this interface was used in the old build infrastructure, it doesn't make sense anymore */ +@ApiStatus.ScheduledForRemoval(inVersion = "192.0") +@Deprecated public interface ArtifactIncrementalCompilerContext { } From 86a4861ca32694547c362038542fc7ae645bddb7 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 5 Feb 2019 16:45:10 +0700 Subject: [PATCH 133/138] ExcessiveRangeCheck.html: typos (IDEA-CR-42349) --- .../src/inspectionDescriptions/ExcessiveRangeCheck.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html b/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html index db5eed4edb1d..c26369c2afa7 100644 --- a/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html +++ b/java/java-impl/src/inspectionDescriptions/ExcessiveRangeCheck.html @@ -1,6 +1,6 @@ -Reports condition chains where value range is checked which could be simplified to single check. E.g. x > 2 && x < 4 could be +Reports condition chains where a value range is checked which could be simplified to a single check. E.g. x > 2 && x < 4 could be simplified to x == 3 or arr.length == 0 || arr.length > 1 could be simplified to arr.length != 1.

New in 2019.1

From 14e8b0a18208742cf285604404a19bbad87f3bd5 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Feb 2019 10:41:45 +0100 Subject: [PATCH 134/138] exile XmlEncodingReference from Comparable caste because it doesn't have consistent "equals" and isn't used in sorted collections anyway --- .../daemon/impl/analysis/encoding/XmlEncodingReference.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java index 0919dccb25fe..6925fda73e5a 100644 --- a/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java +++ b/xml/impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/XmlEncodingReference.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.NotNull; /** * @author cdr */ -public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider, Comparable { +public class XmlEncodingReference extends EncodingReference implements EmptyResolveMessageProvider { private final int myPriority; public XmlEncodingReference(XmlAttributeValue value, final String charsetName, final TextRange rangeInElement, int priority) { @@ -31,7 +31,6 @@ public class XmlEncodingReference extends EncodingReference implements EmptyReso myPriority = priority; } - @Override public int compareTo(@NotNull XmlEncodingReference ref) { return myPriority - ref.myPriority; } From fa9f8866213a663013f9f3c682bf3c5c8de536d2 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Tue, 5 Feb 2019 12:29:22 +0300 Subject: [PATCH 135/138] save a bit of memory: use static fields where that makes sense --- .../intellij/execution/jshell/ExecuteJShellAction.java | 2 +- .../codeStyle/autodetect/DetectIndentAndTypeTest.java | 10 +++++----- .../find/impl/livePreview/LivePreviewController.java | 2 +- .../intellij/ide/util/gotoByName/ChooseByNameBase.java | 2 +- .../ui/componentsList/components/ScrollablePanel.java | 2 +- .../ui/componentsList/layout/VerticalStackLayout.java | 2 +- .../src/com/intellij/openapi/ui/DialogWrapper.java | 4 ++-- .../platform-api/src/com/intellij/ui/JBCardLayout.java | 4 ++-- .../src/com/intellij/ui/tabs/impl/JBTabsImpl.java | 2 +- .../com/intellij/openapi/wm/impl/content/MoreIcon.java | 2 +- .../wm/impl/welcomeScreen/CardActionsPanel.java | 2 +- .../intellij/remote/RemoteSdkCredentialsBuilder.java | 4 ++-- .../src/com/intellij/ui/TableCellEditorWithButton.java | 2 +- .../openapi/util/io/FileUtilPerformanceTest.java | 6 +++--- .../AppendableStorageBackedByResizableMappedFile.java | 2 +- .../util/src/com/intellij/util/io/IntToIntBtree.java | 6 +++--- .../com/intellij/util/ui/tree/WideSelectionTreeUI.java | 2 +- .../jetbrains/java/generate/test/DummyTestBean.java | 2 +- plugins/git4idea/src/git4idea/commands/GitHandler.java | 2 +- .../jetbrains/idea/svn/SvnNativeClientAuthTest.java | 4 ++-- .../tasks/trello/model/TrelloCommentAction.java | 2 +- .../docstrings/NumpyDocStringBuilder.java | 2 +- .../testSrc/com/jetbrains/env/ut/PyUnitTestTask.java | 2 +- .../python/refactoring/PyCodeFragmentTest.java | 6 +++--- .../application/options/editor/WebEditorOptions.java | 2 +- 25 files changed, 39 insertions(+), 39 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java index ecc3295ee03d..5be40ac7cab5 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; */ class ExecuteJShellAction extends AnAction{ private static final AnAction ourInstance = new ExecuteJShellAction(); - private final boolean myIsExecuteContextElement = false; + private static final boolean myIsExecuteContextElement = false; private ExecuteJShellAction() { super(AllIcons.Toolwindows.ToolWindowRun); diff --git a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java index f3f95f3e859a..ba14779ceceb 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java +++ b/java/java-tests/testSrc/com/intellij/java/psi/codeStyle/autodetect/DetectIndentAndTypeTest.java @@ -29,11 +29,11 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; public class DetectIndentAndTypeTest extends LightPlatformCodeInsightFixtureTestCase { private CodeStyleSettings mySettings; - private final String myText = "public class T {\n" + - "\tvoid run() {\n" + - "\t\tint t = 1 + 2;\n" + - "\t}\n" + - "}"; + private static final String myText = "public class T {\n" + + "\tvoid run() {\n" + + "\t\tint t = 1 + 2;\n" + + "\t}\n" + + "}"; @Override public void setUp() throws Exception { diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java index 4b00b9fb1357..a2a165cbc58a 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java @@ -32,7 +32,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep private final Alarm myLivePreviewAlarm; protected SearchResults mySearchResults; private LivePreview myLivePreview; - private final boolean myReplaceDenied = false; + private static final boolean myReplaceDenied = false; private boolean mySuppressUpdate; private boolean myTrackingDocument; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index f0ab0727fe8c..8087a745d8ab 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -134,7 +134,7 @@ public abstract class ChooseByNameBase implements ChooseByNameViewModel { private final int myRebuildDelay; private final Alarm myHideAlarm = new Alarm(); - private final boolean myShowListAfterCompletionKeyStroke = false; + private static final boolean myShowListAfterCompletionKeyStroke = false; protected JBPopup myTextPopup; protected JBPopup myDropdownPopup; diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java index a6a0bb429103..6bc08334b4e7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/components/ScrollablePanel.java @@ -21,7 +21,7 @@ import java.awt.*; public class ScrollablePanel extends JPanel implements Scrollable { private int myUnitHeight = -1; - private final int myUnitWidth = 10; + private static final int myUnitWidth = 10; public ScrollablePanel() { } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java index 8bf1dabd917e..32eb20adc95c 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/componentsList/layout/VerticalStackLayout.java @@ -20,7 +20,7 @@ package com.intellij.openapi.roots.ui.componentsList.layout; import java.awt.*; public class VerticalStackLayout implements LayoutManager2 { - private final int myDefaultHeight = 200; + private static final int myDefaultHeight = 200; /** * Calculates the minimum size dimensions for the specified diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java index e502a2b1cef5..7dfe59565f24 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -2053,8 +2053,8 @@ public abstract class DialogWrapper { } new Thread("DialogWrapper resizer") { - final int time = 200; - final int steps = 7; + static final int time = 200; + static final int steps = 7; @Override public void run() { diff --git a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java index aca9487c472c..1e1e4cef48e0 100644 --- a/platform/platform-api/src/com/intellij/ui/JBCardLayout.java +++ b/platform/platform-api/src/com/intellij/ui/JBCardLayout.java @@ -37,8 +37,8 @@ public class JBCardLayout extends CardLayout { public enum SwipeDirection {FORWARD, BACKWARD, AUTO} private final Map myMap = new LinkedHashMap<>(); - private final int mySwipeTime = 200;//default value, provide setter if need - private final int mySwipeSteps = 20;//default value, provide setter if need + private static final int mySwipeTime = 200;//default value, provide setter if need + private static final int mySwipeSteps = 20;//default value, provide setter if need private final Timer myTimer = UIUtil.createNamedTimer("CardLayoutTimer",Math.max(1, mySwipeTime / mySwipeSteps)); private Component mySwipeFrom = null; private Component mySwipeTo = null; diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java index 006bc106b88a..8742723972f1 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java @@ -128,7 +128,7 @@ public class JBTabsImpl extends JComponent private boolean myPaintBlocked; private BufferedImage myImage; private IdeFocusManager myFocusManager; - private final boolean myAdjustBorders = true; + private static final boolean myAdjustBorders = true; boolean myAddNavigationGroup = true; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java index 562163f38f2c..59458d78d2a1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/MoreIcon.java @@ -29,7 +29,7 @@ public abstract class MoreIcon { private final ActiveIcon myRight = new ActiveIcon(AllIcons.General.ArrowRight, IconLoader.getDisabledIcon(AllIcons.General.ArrowRight)); - protected final int myGap = 2; + protected static final int myGap = 2; protected boolean myLeftPainted; protected boolean myRightPainted; diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java index edfc38ab6a18..dfa018035d3a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/CardActionsPanel.java @@ -40,7 +40,7 @@ import java.util.ArrayList; import java.util.List; public class CardActionsPanel extends JPanel { - private final boolean USE_ICONS = true; + private static final boolean USE_ICONS = true; private final JBCardLayout myLayout = new JBCardLayout(); private final JPanel myContent = new JPanel(myLayout); private int nCards = 0; diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java index 0e8ebba6f785..5a71ca1f2300 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsBuilder.java @@ -23,9 +23,9 @@ import org.jetbrains.annotations.Nullable; */ public class RemoteSdkCredentialsBuilder { private String myInterpreterPath = null; - private final String myHelpersPath = null; + private static final String myHelpersPath = null; private RemoteCredentials myRemoteCredentials = null; - private final String myHelpersDefaultDirName = ".idea_helpers"; + private static final String myHelpersDefaultDirName = ".idea_helpers"; public RemoteSdkCredentials build() { diff --git a/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java b/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java index 359776ff12e1..b08060fad55c 100644 --- a/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java +++ b/platform/platform-impl/src/com/intellij/ui/TableCellEditorWithButton.java @@ -15,7 +15,7 @@ public class TableCellEditorWithButton extends AbstractCellEditor implements Tab protected final MyComponent myComponent; protected final EditorDelegate delegate; - protected final int myClickCountToStart = 1; + protected static final int myClickCountToStart = 1; public TableCellEditorWithButton() { myComponent = new MyComponent(); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java index 0c905cb4303d..540e86600e75 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/util/io/FileUtilPerformanceTest.java @@ -22,9 +22,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class FileUtilPerformanceTest { - private final String myTestPath = "/a/b/c/./d///e/../f/g/h/i/j/"; - private final String myCanonicalPath = "/a/b/c/d/f/g/h/i/j"; - private final String mySimpleTestPath = "file.txt"; + private static final String myTestPath = "/a/b/c/./d///e/../f/g/h/i/j/"; + private static final String myCanonicalPath = "/a/b/c/d/f/g/h/i/j"; + private static final String mySimpleTestPath = "file.txt"; @Test public void toCanonicalPath() { diff --git a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java index a85eaa40e85d..c757caeba542 100644 --- a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java +++ b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java @@ -64,7 +64,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp } private final CompressedAppendableFile myCompressedAppendableFile; - private final boolean testMode = false; + private static final boolean testMode = false; public Data read(final int addr, KeyDescriptor descriptor) throws IOException { Data tempData = null; diff --git a/platform/util/src/com/intellij/util/io/IntToIntBtree.java b/platform/util/src/com/intellij/util/io/IntToIntBtree.java index f790c0485c0b..d423189a4937 100644 --- a/platform/util/src/com/intellij/util/io/IntToIntBtree.java +++ b/platform/util/src/com/intellij/util/io/IntToIntBtree.java @@ -52,10 +52,10 @@ public class IntToIntBtree { private boolean hasZeroKey; private int zeroKeyValue; - private final boolean isLarge = true; + private static final boolean isLarge = true; private final ResizeableMappedFile storage; - private final boolean offloadToSiblingsBeforeSplit = false; - private final boolean indexNodeIsHashTable = true; + private static final boolean offloadToSiblingsBeforeSplit = false; + private static final boolean indexNodeIsHashTable = true; final int metaDataLeafPageLength; final int hashPageCapacity; diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 5e98c607ff28..a3d146d85311 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -63,7 +63,7 @@ public class WideSelectionTreeUI extends BasicTreeUI { private final boolean myWideSelection; private boolean myOldRepaintAllRowValue; private boolean myForceDontPaintLines = false; - private final boolean mySkinny = false; + private static final boolean mySkinny = false; public WideSelectionTreeUI() { this(true, Conditions.alwaysTrue()); diff --git a/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java b/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java index 9277963c06b4..cb09076b2447 100644 --- a/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java +++ b/plugins/generate-tostring/testSrc/org/jetbrains/java/generate/test/DummyTestBean.java @@ -27,7 +27,7 @@ public class DummyTestBean extends Config implements Serializable { public static final String CONST_FIELD = "XXX_XXX"; private static final String CONST_FIELD_PRIV = "XXX_XXX"; - private final transient String tran = "xxx"; + private static final transient String tran = "xxx"; // private static String myStaticString; // private String[] nameStrings = new String[] { "Claus", "Ibsen" }; diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index d862ae995f70..a8a6a6744be3 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -536,7 +536,7 @@ public abstract class GitHandler { @Deprecated private final List myLastOutput = Collections.synchronizedList(new ArrayList<>()); @Deprecated - private final int LAST_OUTPUT_SIZE = 5; + private static final int LAST_OUTPUT_SIZE = 5; @Deprecated private boolean myProgressParameterAllowed = false; @Deprecated diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java index fb92ec4d9165..56bbdfb7ca12 100644 --- a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/SvnNativeClientAuthTest.java @@ -43,8 +43,8 @@ public class SvnNativeClientAuthTest extends SvnTestCase { private boolean mySaveCredentials = false; private boolean myCancelAuth = false; - private final String outHttpUser = "test"; - private final String outHttpPassword = "test"; + private static final String outHttpUser = "test"; + private static final String outHttpPassword = "test"; private final static Url ourHTTP_URL = parseUrl("http://svnsrvtest/stuff/autoTest", false); private final static Url ourHTTPS_URL = parseUrl("https://svnsrvtest:443/TestSSL/autoTest", false); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java index f5d13b07f378..d5c8f7fa3536 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/trello/model/TrelloCommentAction.java @@ -32,7 +32,7 @@ public class TrelloCommentAction extends Comment { private static class Data { - private final String text = ""; + private static final String text = ""; private TrelloBoard board; private TrelloCard card; } diff --git a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java index db89d46fce9c..7b9496dd80a5 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/NumpyDocStringBuilder.java @@ -28,7 +28,7 @@ public class NumpyDocStringBuilder extends SectionBasedDocStringBuilder { public static final String DEFAULT_CONTINUATION_INDENT = PyIndentUtil.FOUR_SPACES; public static final char DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL = '-'; - private final char myUnderlineSymbol = DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL; + private static final char myUnderlineSymbol = DEFAULT_SECTION_TITLE_UNDERLINE_SYMBOL; public NumpyDocStringBuilder() { // Sections are not indented and continuation indent of 4 spaces like in Numpy sources diff --git a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java index 06012a884f1a..447a312495ac 100644 --- a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java +++ b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java @@ -75,7 +75,7 @@ import java.util.List; public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask { protected ProcessHandler myProcessHandler; - private final boolean shouldPrintOutput = false; + private static final boolean shouldPrintOutput = false; /** * Test root node */ diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java index f8cfc7969037..beb5682bffbf 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyCodeFragmentTest.java @@ -40,9 +40,9 @@ public class PyCodeFragmentTest extends LightMarkedTestCase { return PythonTestUtil.getTestDataPath() + "/codeInsight/codefragment/"; } - final private String BEGIN_MARKER = ""; - final private String END_MARKER = ""; - final private String RESULT_MARKER = ""; + static final private String BEGIN_MARKER = ""; + static final private String END_MARKER = ""; + static final private String RESULT_MARKER = ""; private void doTest(Pair... files2Create) throws Exception { final String testName = getTestName(false).toLowerCase(); diff --git a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java index 61df0b54b68c..769b832e5e52 100644 --- a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java +++ b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.Nullable; storages = @Storage("editor.xml") ) public class WebEditorOptions implements PersistentStateComponent { - private final boolean myShowCssColorPreviewInGutter = true; + private static final boolean myShowCssColorPreviewInGutter = true; private boolean mySelectWholeCssIdentifierOnDoubleClick = true; private boolean myShowCssInlineColorPreview = false; private boolean myAutomaticallyInsertClosingTag = true; From 8fbedc29f3dccd49c02a51f53adcb6cc792b9637 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 5 Feb 2019 13:12:58 +0300 Subject: [PATCH 136/138] tests: move InMemoryCompiler to intellij.java.testFramework module so it can be reused in other tests --- .../compiler/JavaInMemoryCompiler.java | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java diff --git a/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java b/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java new file mode 100644 index 000000000000..442d2a12c2f0 --- /dev/null +++ b/java/testFramework/src/com/intellij/compiler/JavaInMemoryCompiler.java @@ -0,0 +1,115 @@ +// Copyright 2000-2019 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.compiler; + +import org.intellij.lang.annotations.Language; + +import javax.tools.*; +import java.io.*; +import java.net.URI; +import java.util.*; + +/** + * @author Bas Leijdekkers + */ +public class JavaInMemoryCompiler { + + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + private final JavaMemFileManager myFileManager = new JavaMemFileManager(); + private final JavaCompiler myCompiler = ToolProvider.getSystemJavaCompiler(); + + public Map compile(String className, @Language("JAVA") String code) { + final DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + final Iterable compilationUnits = Collections.singletonList(new JavaSourceFromString(className, code)); + final Iterable options = Arrays.asList("-g"); // generate debugging info. + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + final OutputStreamWriter out = new OutputStreamWriter(System.err); + final Boolean success = myCompiler.getTask(out, myFileManager, diagnostics, options, null, compilationUnits).call(); + + if (!success.booleanValue()) { + final StringWriter writer = new StringWriter(); + for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { + writer.write(diagnostic.getMessage(Locale.ENGLISH)); + writer.write(" on line " + diagnostic.getLineNumber()); + writer.write("\n"); + } + throw new RuntimeException(writer.toString()); + } + final List classFiles = myFileManager.getClassFiles(); + final Map result = new HashMap<>(2); + for (InMemoryClassFile classFile : classFiles) { + result.put(classFile.getClassName(), classFile.getBytes()); + } + return result; + } + + public static class JavaSourceFromString extends SimpleJavaFileObject { + + final String myCode; + + JavaSourceFromString(String className, String code) { + super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.myCode = code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return myCode; + } + } + + public static class InMemoryClassFile extends SimpleJavaFileObject { + + private final String myClassName; + ByteArrayOutputStream myOutputStream = new ByteArrayOutputStream(); + + public InMemoryClassFile(String className) { + super(URI.create("class:///" + className.replace('.', '/') + ".class"), Kind.CLASS); + myClassName = className; + } + + public String getClassName() { + return myClassName; + } + + public byte[] getBytes() { + return myOutputStream.toByteArray(); + } + + @Override + public OutputStream openOutputStream() { + myOutputStream.reset(); + return myOutputStream; + } + } + + public static class JavaMemFileManager extends ForwardingJavaFileManager { + + private final List myClassFiles = new ArrayList<>(2); + + public JavaMemFileManager() { + super(ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) + throws IOException { + if (StandardLocation.CLASS_OUTPUT == location && JavaFileObject.Kind.CLASS == kind) { + final InMemoryClassFile file = new InMemoryClassFile(className); + myClassFiles.add(file); + return file; + } + else { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + } + + public List getClassFiles() { + return myClassFiles; + } + + @Override + public ClassLoader getClassLoader(Location location) { + return null; + } + } +} \ No newline at end of file From 7fcfc12f088bb8444306ba0a9b743638ddbb3dcc Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Tue, 5 Feb 2019 13:26:46 +0300 Subject: [PATCH 137/138] added map-like debugger renderer --- .../com/intellij/util/keyFMap/KeyFMap.java | 18 +++------------ .../util/keyFMap/KeyFMapRenderer.java | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java diff --git a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java index 4971f9914b50..1b388dbb824d 100644 --- a/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/KeyFMap.java @@ -1,21 +1,8 @@ -/* - * Copyright 2000-2012 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-2019 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.util.keyFMap; import com.intellij.openapi.util.Key; +import org.jetbrains.annotations.Debugger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +17,7 @@ import org.jetbrains.annotations.Nullable; * * @author peter */ +@Debugger.Renderer(text = "\"size = \" + size()", hasChildren = "!isEmpty()", childrenArray = "KeyFMapRenderer.childrenArray(this)") public interface KeyFMap { /** * An empty {@code KeyFMap}. No additional instances of empty {@code KeyFMap} should be created as they are indistinguishable. diff --git a/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java b/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java new file mode 100644 index 000000000000..5b7151a93d84 --- /dev/null +++ b/platform/util/src/com/intellij/util/keyFMap/KeyFMapRenderer.java @@ -0,0 +1,22 @@ +// Copyright 2000-2019 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.util.keyFMap; + +import com.intellij.openapi.util.Key; + +import java.util.AbstractMap; +import java.util.Map; + +// Used in KeyFMap debugger renderer +@SuppressWarnings("unused") +class KeyFMapRenderer { + static Map.Entry[] childrenArray(KeyFMap map) { + Key[] keys = map.getKeys(); + int length = map.size(); + Map.Entry[] res = new Map.Entry[length]; + for (int i = 0; i < length; i++) { + Key key = keys[i]; + res[i] = new AbstractMap.SimpleImmutableEntry(key, map.get(key)); + } + return res; + } +} From 37a48d8e0b0f93c46acf4f18c475230e274aaf51 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 5 Feb 2019 11:30:37 +0100 Subject: [PATCH 138/138] [tests] improves file lookup in DirectoryIndexRestoreTest --- .../roots/impl/DirectoryIndexRestoreTest.java | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java b/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java index b75f06133104..92ddc8cce51b 100644 --- a/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.java +++ b/java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexRestoreTest.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-2019 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.java.openapi.roots.impl; import com.intellij.openapi.roots.ContentIterator; @@ -44,11 +30,11 @@ public class DirectoryIndexRestoreTest extends IdeaTestCase { LocalFileSystem fs = LocalFileSystem.getInstance(); File temp = createTempDirectory(); - myTempVFile = fs.findFileByIoFile(temp); + myTempVFile = fs.refreshAndFindFileByIoFile(temp); assertNotNull(myTempVFile); File root = new File(temp, "top/d1/d2/root"); assertTrue(root.mkdirs()); - VirtualFile rootVFile = fs.findFileByIoFile(root); + VirtualFile rootVFile = fs.refreshAndFindFileByIoFile(root); assertNotNull(rootVFile); VirtualFile moduleDir = createChildDirectory(rootVFile, "module");