From 18deca93e2390d44a2fdb01a78bcba404073b2dc Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 31 May 2016 16:51:00 +0300 Subject: [PATCH 01/35] IDEA-146153 Text label disappears when click on it caused by: c000a5c169ab63d5b5fb012f51b3100d7ee1a313 --- platform/platform-api/src/com/intellij/ui/CheckBoxList.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java index edf9be653c90..3bf162eacf61 100644 --- a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java +++ b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java @@ -187,6 +187,7 @@ public class CheckBoxList extends JBList { public void addItem(T item, String text, boolean selected) { JCheckBox checkBox = new JCheckBox(text, selected); + checkBox.setOpaque(true); // to paint selection background myItemMap.put(item, checkBox); //noinspection unchecked ((DefaultListModel)getModel()).addElement(checkBox); From 0166710b69fb638d7cf5751d728be4cbcccdda8f Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Tue, 31 May 2016 14:22:50 +0300 Subject: [PATCH 02/35] added ability to add tests and suites without run configuration, more accurate namings --- .../testIntegration/RecentTestsData.kt | 79 +++++++++++-------- .../RecentTestsListProvider.java | 12 ++- .../testIntegration/RunConfigurationEntry.kt | 13 ++- .../testIntergration/RecentTestsTest.kt | 32 ++++---- 4 files changed, 78 insertions(+), 58 deletions(-) diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt index b28de358ea41..8e77286b5cd9 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt @@ -16,52 +16,70 @@ package com.intellij.testIntegration import com.intellij.execution.RunnerAndConfigurationSettings -import com.intellij.execution.testframework.sm.runner.states.TestStateInfo +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.util.containers.ContainerUtil import java.util.* +fun SuiteEntry.isMyTest(test: SingleTestEntry): Boolean { + val testName = VirtualFileManager.extractPath(test.url) + return testName.startsWith(this.suiteName) +} + class RecentTestsData { private val runConfigurationSuites = hashMapOf() - private var testsWithoutSuites: MutableList = ContainerUtil.newArrayList() - fun addSuite(url: String, - magnitude: TestStateInfo.Magnitude, - runDate: Date, - runConfiguration: RunnerAndConfigurationSettings) + private var unmatchedRunConfigurationTests: MutableList = arrayListOf() + + private val urlSuites = mutableListOf() + private var unmatchedUrlTests = mutableListOf() + + fun addUrlSuite(url: String, magnitude: Magnitude, runDate: Date) { + val suite = SuiteEntry(url, magnitude, runDate) + + unmatchedUrlTests.filter { suite.isMyTest(it) }.forEach { suite.addTest(it) } + unmatchedUrlTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) + + urlSuites.add(suite) + } + + fun addRunConfigurationSuite(url: String, + magnitude: Magnitude, + runDate: Date, + runConfiguration: RunnerAndConfigurationSettings) { - val suiteInfo = SuiteEntry(url, magnitude, runDate, runConfiguration) + val suite = SuiteEntry(url, magnitude, runDate) + + unmatchedRunConfigurationTests.filter { suite.isMyTest(it) }.forEach { suite.addTest(it) } + unmatchedRunConfigurationTests = unmatchedRunConfigurationTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) val configurationId = runConfiguration.uniqueID val suitePack = runConfigurationSuites[configurationId] if (suitePack != null) { - suitePack.addSuite(suiteInfo) - return - } - - runConfigurationSuites[configurationId] = RunConfigurationEntry(runConfiguration, suiteInfo) - } - - - fun addTest(url: String, - magnitude: TestStateInfo.Magnitude, - runDate: Date, - runConfiguration: RunnerAndConfigurationSettings) { - - val testInfo = SingleTestEntry(url, magnitude, runDate, runConfiguration) - - val suite = findSuite(url, runConfiguration) - if (suite != null) { - suite.addTest(testInfo) + suitePack.addSuite(suite) return } - testsWithoutSuites.add(testInfo) + runConfigurationSuites[configurationId] = RunConfigurationEntry(runConfiguration, suite) } - private fun findSuite(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteEntry? { + fun addUrlTest(url: String, magnitude: Magnitude, runDate: Date) { + val test = SingleTestEntry(url, magnitude, runDate) + findUrlSuite(url)?.addTest(test) ?: unmatchedUrlTests.add(test) + } + + fun addRunConfigurationTest(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings) { + val test = SingleTestEntry(url, magnitude, runDate) + findRunConfigurationTest(url, runConfiguration)?.addTest(test) ?: unmatchedRunConfigurationTests.add(test) + } + + private fun findUrlSuite(url: String) = urlSuites.find { + val testName = VirtualFileManager.extractPath(url) + testName.startsWith(it.suiteName) + } + + private fun findRunConfigurationTest(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteEntry? { val pack: RunConfigurationEntry = runConfigurationSuites[runConfiguration.uniqueID] ?: return null val testName = VirtualFileManager.extractPath(url) @@ -75,10 +93,7 @@ class RecentTestsData { } fun getTestsToShow(): List { - testsWithoutSuites.forEach { - val url = it.url - findSuite(url, it.runConfiguration)?.addTest(it) - } + assert(unmatchedRunConfigurationTests.isEmpty()) val packsByDate = runConfigurationSuites.values.sortedByDescending { it.runDate } return packsByDate.fold(listOf(), { list, pack -> list + pack.entriesToShow() }) diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java index 1619134f6919..87289e3612dc 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java @@ -100,11 +100,19 @@ public class RecentTestsListProvider { RunnerAndConfigurationSettings runConfiguration = myConfigurationProvider.getConfiguration(record); if (TestLocator.isSuite(url)) { if (runConfiguration != null) { - data.addSuite(url, magnitude, record.date, runConfiguration); + data.addRunConfigurationSuite(url, magnitude, record.date, runConfiguration); + } + else { + data.addUrlSuite(url, magnitude, record.date); } } else { - data.addTest(url, magnitude, record.date, runConfiguration); + if (runConfiguration != null) { + data.addRunConfigurationTest(url, magnitude, record.date, runConfiguration); + } + else { + data.addUrlTest(url, magnitude, record.date); + } } } diff --git a/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt b/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt index bb23cb41a909..7f7b1357e666 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt @@ -35,10 +35,9 @@ interface RecentTestsPopupEntry { open fun navigatableElement(locator: TestLocator): PsiElement? = null } -open class SingleTestEntry(val url: String, - override val magnitude: TestStateInfo.Magnitude, - override val runDate: Date, - val runConfiguration: RunnerAndConfigurationSettings) : RecentTestsPopupEntry +open class SingleTestEntry(val url: String, + override val magnitude: TestStateInfo.Magnitude, + override val runDate: Date) : RecentTestsPopupEntry { override val presentation = VirtualFileManager.extractPath(url) @@ -52,10 +51,8 @@ open class SingleTestEntry(val url: String, } -class SuiteEntry(url: String, magnitude: TestStateInfo.Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings) - : SingleTestEntry(url, magnitude, runDate, runConfiguration) -{ - +class SuiteEntry(url: String, magnitude: TestStateInfo.Magnitude, runDate: Date) : SingleTestEntry(url, magnitude, runDate) { + private val tests = hashSetOf() override val testsUrls: List diff --git a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt index ab7fe6a8b8df..82a76ae8aeca 100644 --- a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt +++ b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt @@ -40,14 +40,14 @@ class RecentTestsStepTest: LightIdeaTestCase() { } fun `test all tests passed`() { - data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(1) @@ -56,13 +56,13 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if one failed in run configuration show failed suite`() { - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addRunConfigurationSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() @@ -73,9 +73,9 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if configuration with single test show failed test`() { - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(2) From 32b3650040f3f53d2e3da652f4f8d26cfd625386 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Tue, 31 May 2016 16:10:14 +0300 Subject: [PATCH 03/35] Fixed EA-83158, show suites without run configuration --- .../testIntegration/RecentTestsData.kt | 76 +++++++++++-------- .../RecentTestsListProvider.java | 14 +--- .../testIntergration/RecentTestsTest.kt | 43 +++++++---- 3 files changed, 74 insertions(+), 59 deletions(-) diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt index 8e77286b5cd9..2f4206580fed 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt @@ -29,49 +29,57 @@ class RecentTestsData { private val runConfigurationSuites = hashMapOf() - private var unmatchedRunConfigurationTests: MutableList = arrayListOf() + private var unmatchedRunConfigurationTests = arrayListOf() private val urlSuites = mutableListOf() private var unmatchedUrlTests = mutableListOf() - fun addUrlSuite(url: String, magnitude: Magnitude, runDate: Date) { + + fun addSuite(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings?) { val suite = SuiteEntry(url, magnitude, runDate) + if (runConfiguration != null) { + addRunConfigurationSuite(suite, runConfiguration) + } + else { + addUrlSuite(suite) + } + } - unmatchedUrlTests.filter { suite.isMyTest(it) }.forEach { suite.addTest(it) } - unmatchedUrlTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) + fun addTest(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings?) { + val test = SingleTestEntry(url, magnitude, runDate) + if (runConfiguration != null) { + addRunConfigurationTest(test, runConfiguration) + } + else { + addUrlTest(test) + } + } + + private fun addUrlSuite(suite: SuiteEntry) { + val suiteTests = unmatchedUrlTests.filter { suite.isMyTest(it) } + suiteTests.forEach { suite.addTest(it) } + + unmatchedUrlTests = unmatchedUrlTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) urlSuites.add(suite) } - fun addRunConfigurationSuite(url: String, - magnitude: Magnitude, - runDate: Date, - runConfiguration: RunnerAndConfigurationSettings) - { - - val suite = SuiteEntry(url, magnitude, runDate) - - unmatchedRunConfigurationTests.filter { suite.isMyTest(it) }.forEach { suite.addTest(it) } + private fun addRunConfigurationSuite(suite: SuiteEntry, config: RunnerAndConfigurationSettings) { + val suiteTests = unmatchedRunConfigurationTests.filter { suite.isMyTest(it) } + suiteTests.forEach { suite.addTest(it) } + unmatchedRunConfigurationTests = unmatchedRunConfigurationTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) - val configurationId = runConfiguration.uniqueID - val suitePack = runConfigurationSuites[configurationId] - if (suitePack != null) { - suitePack.addSuite(suite) - return - } - - runConfigurationSuites[configurationId] = RunConfigurationEntry(runConfiguration, suite) + val id = config.uniqueID + runConfigurationSuites[id]?.addSuite(suite) ?: runConfigurationSuites.put(id, RunConfigurationEntry(config, suite)) } - fun addUrlTest(url: String, magnitude: Magnitude, runDate: Date) { - val test = SingleTestEntry(url, magnitude, runDate) - findUrlSuite(url)?.addTest(test) ?: unmatchedUrlTests.add(test) + private fun addUrlTest(test: SingleTestEntry) { + findUrlSuite(test.url)?.addTest(test) ?: unmatchedUrlTests.add(test) } - fun addRunConfigurationTest(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings) { - val test = SingleTestEntry(url, magnitude, runDate) - findRunConfigurationTest(url, runConfiguration)?.addTest(test) ?: unmatchedRunConfigurationTests.add(test) + private fun addRunConfigurationTest(test: SingleTestEntry, runConfiguration: RunnerAndConfigurationSettings) { + findRunConfigurationSuite(test.url, runConfiguration)?.addTest(test) ?: unmatchedRunConfigurationTests.add(test) } private fun findUrlSuite(url: String) = urlSuites.find { @@ -79,7 +87,7 @@ class RecentTestsData { testName.startsWith(it.suiteName) } - private fun findRunConfigurationTest(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteEntry? { + private fun findRunConfigurationSuite(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteEntry? { val pack: RunConfigurationEntry = runConfigurationSuites[runConfiguration.uniqueID] ?: return null val testName = VirtualFileManager.extractPath(url) @@ -94,9 +102,15 @@ class RecentTestsData { fun getTestsToShow(): List { assert(unmatchedRunConfigurationTests.isEmpty()) - - val packsByDate = runConfigurationSuites.values.sortedByDescending { it.runDate } - return packsByDate.fold(listOf(), { list, pack -> list + pack.entriesToShow() }) + val allEntries: List = runConfigurationSuites.values + urlSuites + return allEntries + .sortedByDescending { it.runDate } + .fold(listOf(), { popupList, currentEntry -> + when (currentEntry) { + is RunConfigurationEntry -> popupList + currentEntry.entriesToShow() + else -> popupList + currentEntry + } + }) } } diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java index 87289e3612dc..66ff8617809e 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java @@ -99,20 +99,10 @@ public class RecentTestsListProvider { RunnerAndConfigurationSettings runConfiguration = myConfigurationProvider.getConfiguration(record); if (TestLocator.isSuite(url)) { - if (runConfiguration != null) { - data.addRunConfigurationSuite(url, magnitude, record.date, runConfiguration); - } - else { - data.addUrlSuite(url, magnitude, record.date); - } + data.addSuite(url, magnitude, record.date, runConfiguration); } else { - if (runConfiguration != null) { - data.addRunConfigurationTest(url, magnitude, record.date, runConfiguration); - } - else { - data.addUrlTest(url, magnitude, record.date); - } + data.addTest(url, magnitude, record.date, runConfiguration); } } diff --git a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt index 82a76ae8aeca..d221e8b6769b 100644 --- a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt +++ b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt @@ -24,6 +24,9 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import java.util.* +fun String.suite() = "java:suite://$this" +fun String.test() = "java:test://$this" + class RecentTestsStepTest: LightIdeaTestCase() { lateinit var data: RecentTestsData @@ -38,16 +41,24 @@ class RecentTestsStepTest: LightIdeaTestCase() { `when`(allTests.name).thenAnswer { "all tests" } now = Date() } + + fun `test show suites without run configuration`() { + data.addTest("Test.x".test(), TestStateInfo.Magnitude.PASSED_INDEX, now, null) + data.addSuite("Test".suite(), TestStateInfo.Magnitude.PASSED_INDEX, now, null) + + val tests = data.getTestsToShow() + assertThat(tests).hasSize(1) + } fun `test all tests passed`() { - data.addRunConfigurationTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(1) @@ -56,13 +67,13 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if one failed in run configuration show failed suite`() { - data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addRunConfigurationSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() @@ -73,9 +84,9 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if configuration with single test show failed test`() { - data.addRunConfigurationSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addRunConfigurationTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) + data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(2) From eb93ea47aa00afd10e04902a27a283f326029878 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Tue, 31 May 2016 16:55:34 +0300 Subject: [PATCH 04/35] removed assertion, test prettified --- .../testIntegration/RecentTestsData.kt | 1 - .../testIntergration/RecentTestsTest.kt | 45 ++++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt index 2f4206580fed..baf149ac450c 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt @@ -101,7 +101,6 @@ class RecentTestsData { } fun getTestsToShow(): List { - assert(unmatchedRunConfigurationTests.isEmpty()) val allEntries: List = runConfigurationSuites.values + urlSuites return allEntries .sortedByDescending { it.runDate } diff --git a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt index d221e8b6769b..6424974bad14 100644 --- a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt +++ b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt @@ -16,7 +16,8 @@ package com.intellij.testIntergration import com.intellij.execution.RunnerAndConfigurationSettings -import com.intellij.execution.testframework.sm.runner.states.TestStateInfo +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.FAILED_INDEX +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.PASSED_INDEX import com.intellij.testFramework.LightIdeaTestCase import com.intellij.testIntegration.RecentTestsData import org.assertj.core.api.Assertions.assertThat @@ -43,22 +44,22 @@ class RecentTestsStepTest: LightIdeaTestCase() { } fun `test show suites without run configuration`() { - data.addTest("Test.x".test(), TestStateInfo.Magnitude.PASSED_INDEX, now, null) - data.addSuite("Test".suite(), TestStateInfo.Magnitude.PASSED_INDEX, now, null) + data.addTest("Test.x".test(), PASSED_INDEX, now, null) + data.addSuite("Test".suite(), PASSED_INDEX, now, null) val tests = data.getTestsToShow() assertThat(tests).hasSize(1) } fun `test all tests passed`() { - data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textYYY", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textZZZ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textQQQ", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("Test.textXXX".test(), PASSED_INDEX, now, allTests) + data.addSuite("Test".suite(), PASSED_INDEX, now, allTests) + data.addSuite("JFSDTest".suite(), PASSED_INDEX, now, allTests) + data.addTest("Test.textYYY".test(), PASSED_INDEX, now, allTests) + data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), PASSED_INDEX, now, allTests) + data.addTest("Test.textZZZ".test(), PASSED_INDEX, now, allTests) + data.addTest("Test.textQQQ".test(), PASSED_INDEX, now, allTests) + data.addTest("JFSDTest.testUnconditionalAlignmentErrorneous".test(), PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(1) @@ -67,31 +68,31 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if one failed in run configuration show failed suite`() { - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addSuite("java:suite://Test", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("JFSDTest".suite(), FAILED_INDEX, now, allTests) + data.addSuite("Test".test(), PASSED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), FAILED_INDEX, now, allTests) + data.addTest("JFSDTest.testUnconditionalAlignmentErrorneous".test(), PASSED_INDEX, now, allTests) - data.addTest("java:test://Test.textXXX", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addTest("Test.textXXX".test(), PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(2) - assertThat(tests[0].presentation).isEqualTo("JavaFormatterSuperDuperTest") + assertThat(tests[0].presentation).isEqualTo("JFSDTest") assertThat(tests[1].presentation).isEqualTo("all tests") } fun `test if configuration with single test show failed test`() { - data.addSuite("java:suite://JavaFormatterSuperDuperTest", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt", TestStateInfo.Magnitude.FAILED_INDEX, now, allTests) - data.addTest("java:test://JavaFormatterSuperDuperTest.testUnconditionalAlignmentErrorneous", TestStateInfo.Magnitude.PASSED_INDEX, now, allTests) + data.addSuite("JFSDTest".suite(), FAILED_INDEX, now, allTests) + data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), FAILED_INDEX, now, allTests) + data.addTest("JFSDTest.testUnconditionalAlignmentErrorneous".test(), PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() assertThat(tests).hasSize(2) - assertThat(tests[0].presentation).isEqualTo("JavaFormatterSuperDuperTest.testItMakesMeSadToFixIt") - assertThat(tests[1].presentation).isEqualTo("JavaFormatterSuperDuperTest") + assertThat(tests[0].presentation).isEqualTo("JFSDTest.testItMakesMeSadToFixIt") + assertThat(tests[1].presentation).isEqualTo("JFSDTest") } From 76501308f5e2ca224014427907b44ec9d31a7863 Mon Sep 17 00:00:00 2001 From: Ivan Bessonov Date: Tue, 31 May 2016 17:26:57 +0300 Subject: [PATCH 05/35] IDEA-CR-11140 test moved from GwtStudio to xml-tests --- .../xml/XmlEntityManagerCachingTest.java | 58 +++++++++++++++++++ xml/tests/testData/xml/UiBinder.xsd | 30 ++++++++++ .../xml/XmlEntityManagerCaching.ui.xml | 5 ++ xml/tests/testData/xml/xhtml.ent | 1 + 4 files changed, 94 insertions(+) create mode 100644 xml/tests/src/com/intellij/xml/XmlEntityManagerCachingTest.java create mode 100644 xml/tests/testData/xml/UiBinder.xsd create mode 100644 xml/tests/testData/xml/XmlEntityManagerCaching.ui.xml create mode 100644 xml/tests/testData/xml/xhtml.ent diff --git a/xml/tests/src/com/intellij/xml/XmlEntityManagerCachingTest.java b/xml/tests/src/com/intellij/xml/XmlEntityManagerCachingTest.java new file mode 100644 index 000000000000..8091efbfe154 --- /dev/null +++ b/xml/tests/src/com/intellij/xml/XmlEntityManagerCachingTest.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package com.intellij.xml; + +import com.intellij.javaee.ExternalResourceManagerExImpl; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; +import com.intellij.xml.util.CheckXmlFileWithXercesValidatorInspection; + +import java.io.File; + +/** + * @author ibessonov + */ +public class XmlEntityManagerCachingTest extends LightPlatformCodeInsightFixtureTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + + ExternalResourceManagerExImpl.registerResourceTemporarily("http://dl.google.com/gwt/DTD/xhtml.ent", + getTestDataPath() + "xhtml.ent", getTestRootDisposable()); + ExternalResourceManagerExImpl.registerResourceTemporarily("urn:ui:com.google.gwt.uibinder", + getTestDataPath() + "UiBinder.xsd", getTestRootDisposable()); + + myFixture.enableInspections(CheckXmlFileWithXercesValidatorInspection.class); + } + + public void testXmlEntityManagerCaching() { + myFixture.configureByFile(getTestName(false) + ".ui.xml"); + myFixture.checkHighlighting(); + myFixture.type('\b'); // edit content, document has to be valid after that + myFixture.checkHighlighting(); + } + + @Override + protected String getBasePath() { + return "/xml/tests/testData/xml/"; + } + + @Override + protected String getTestDataPath() { + return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + getBasePath(); + } +} diff --git a/xml/tests/testData/xml/UiBinder.xsd b/xml/tests/testData/xml/UiBinder.xsd new file mode 100644 index 000000000000..c44dd5c7fd50 --- /dev/null +++ b/xml/tests/testData/xml/UiBinder.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/xml/tests/testData/xml/XmlEntityManagerCaching.ui.xml b/xml/tests/testData/xml/XmlEntityManagerCaching.ui.xml new file mode 100644 index 000000000000..197ce309c79e --- /dev/null +++ b/xml/tests/testData/xml/XmlEntityManagerCaching.ui.xml @@ -0,0 +1,5 @@ + + + Hello World + \ No newline at end of file diff --git a/xml/tests/testData/xml/xhtml.ent b/xml/tests/testData/xml/xhtml.ent new file mode 100644 index 000000000000..21cbb5442c58 --- /dev/null +++ b/xml/tests/testData/xml/xhtml.ent @@ -0,0 +1 @@ + \ No newline at end of file From ceb2b9bf5343f5d5c190b45a4a74116a196841ac Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 31 May 2016 16:24:11 +0200 Subject: [PATCH 06/35] performLaterWhenAllCommitted should work from within commit handler --- .../psi/impl/PsiDocumentManagerBase.java | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java index 7d6673ece18f..2b64e76ba2ba 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiDocumentManagerBase.java @@ -533,30 +533,34 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen @Override public void performLaterWhenAllCommitted(@NotNull final Runnable runnable) { - final ModalityState modalityState = ModalityState.current(); - UIUtil.invokeLaterIfNeeded(new Runnable() { + final ModalityState modalityState = ModalityState.defaultModalityState(); + final Runnable whenAllCommitted = new Runnable() { @Override public void run() { - performWhenAllCommitted(new Runnable() { + ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - // later because we may end up in write action here if there was a synchronous commit - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (hasUncommitedDocuments()) { - // no luck, will try later - performLaterWhenAllCommitted(runnable); - } - else { - runnable.run(); - } - } - }, modalityState, myProject.getDisposed()); + if (hasUncommitedDocuments()) { + // no luck, will try later + performLaterWhenAllCommitted(runnable); + } + else { + runnable.run(); + } } - }); + }, modalityState, myProject.getDisposed()); } - }); + }; + if (ApplicationManager.getApplication().isDispatchThread() && isInsideCommitHandler()) { + whenAllCommitted.run(); + } else { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + performWhenAllCommitted(whenAllCommitted); + } + }); + } } private static class CompositeRunnable extends ArrayList implements Runnable { @@ -586,7 +590,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen if (!hasUncommitedDocuments() && !actionsWhenAllDocumentsAreCommitted.isEmpty()) { List> entries = new ArrayList>(new LinkedHashMap(actionsWhenAllDocumentsAreCommitted).entrySet()); - weAreInsideAfterCommitHandler(); + beforeCommitHandler(); try { for (Map.Entry entry : entries) { @@ -605,15 +609,19 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen } } - private void weAreInsideAfterCommitHandler() { + private void beforeCommitHandler() { actionsWhenAllDocumentsAreCommitted.put(PERFORM_ALWAYS_KEY, EmptyRunnable.getInstance()); // to prevent listeners from registering new actions during firing } private void checkWeAreOutsideAfterCommitHandler() { - if (actionsWhenAllDocumentsAreCommitted.get(PERFORM_ALWAYS_KEY) == EmptyRunnable.getInstance()) { + if (isInsideCommitHandler()) { throw new IncorrectOperationException("You must not call performWhenAllCommitted()/cancelAndRunWhenCommitted() from within after-commit handler"); } } + private boolean isInsideCommitHandler() { + return actionsWhenAllDocumentsAreCommitted.get(PERFORM_ALWAYS_KEY) == EmptyRunnable.getInstance(); + } + @Override public void addListener(@NotNull Listener listener) { myListeners.add(listener); From d3514a3006d5df48500e56e9e446942c29b4367a Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 31 May 2016 16:25:56 +0200 Subject: [PATCH 07/35] update usage preview immediately if everything is committed (IDEA-CR-11111, EA-83054 - assert: PsiDocumentManagerBase.commitAllDocuments) --- .../intellij/usages/impl/UsageContextPanelBase.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageContextPanelBase.java b/platform/usageView/src/com/intellij/usages/impl/UsageContextPanelBase.java index 2dd983353f16..8ec737a0bc87 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageContextPanelBase.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageContextPanelBase.java @@ -58,10 +58,16 @@ public abstract class UsageContextPanelBase extends JPanel implements UsageConte @Override public final void updateLayout(@Nullable final List infos) { - PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted(() -> { - if (isDisposed || myProject.isDisposed()) return; + PsiDocumentManager pdm = PsiDocumentManager.getInstance(myProject); + if (!pdm.hasUncommitedDocuments()) { updateLayoutLater(infos); - }); + } else { + pdm.performLaterWhenAllCommitted(() -> { + if (isDisposed || myProject.isDisposed()) return; + updateLayoutLater(infos); + }); + } + } protected abstract void updateLayoutLater(@Nullable List infos); From 1bcb4977835f36e22aa9d6fbae931b6a30c748ec Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Tue, 31 May 2016 13:29:34 +0300 Subject: [PATCH 08/35] handle values containing multiple tokens also try to reuse old escaping for quotes #WEB-21365 fixed --- .../XmlAttributeValueManipulator.java | 45 +++++++------------ .../XmlProcessingInstructionManipulator.java | 35 ++++++++++++++- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java index efb0a79862fb..f41d1d30ec63 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java @@ -20,15 +20,12 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; import com.intellij.psi.PsiElement; +import com.intellij.psi.XmlElementFactory; import com.intellij.psi.impl.CheckUtil; -import com.intellij.psi.impl.source.tree.CompositeElement; -import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.LeafElement; -import com.intellij.psi.impl.source.tree.SharedImplUtil; -import com.intellij.psi.tree.IElementType; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTokenType; -import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -44,37 +41,25 @@ public class XmlAttributeValueManipulator extends AbstractElementManipulator T handleContentChange(T element, - TextRange range, - String newContent, - final IElementType tokenType) { CheckUtil.checkWritable(element); - final CompositeElement attrNode = (CompositeElement)element.getNode(); - final ASTNode valueNode = attrNode.findLeafElementAt(range.getStartOffset()); - LOG.assertTrue(valueNode != null, "Leaf not found in " + attrNode + " at offset " + range.getStartOffset() + " in element " + element); - final PsiElement elementToReplace = valueNode.getPsi(); String text; + final String oldText = element.getText(); try { - text = elementToReplace.getText(); - final int offsetInParent = elementToReplace.getStartOffsetInParent(); - String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent); - String textAfterRange = text.substring(range.getEndOffset()- offsetInParent, text.length()); - newContent = element.getText().startsWith("'") || element.getText().endsWith("'") ? - newContent.replace("'", "'") : newContent.replace("\"", """); - text = textBeforeRange + newContent + textAfterRange; + String textBeforeRange = oldText.substring(0, range.getStartOffset()); + String textAfterRange = oldText.substring(range.getEndOffset(), oldText.length()); + newContent = oldText.startsWith("'") || oldText.endsWith("'") ? + newContent.replace("'", oldText.contains("'") ? "'" : "'") : + newContent.replace("\"", oldText.contains(""") ? """ : """); + text = ""; } catch(StringIndexOutOfBoundsException e) { - LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e); + LOG.error("Range: " + range + " in text: '" + oldText + "'", e); throw e; } - final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(attrNode); - final LeafElement newValueElement = Factory.createSingleLeafElement(tokenType, text, charTableByTree, element.getManager()); - - attrNode.replaceChildInternal(valueNode, newValueElement); - return element; + final XmlTag tag = XmlElementFactory.getInstance(element.getProject()).createTagFromText(text); + final XmlAttribute attribute = tag.getAttribute("value"); + assert attribute != null && attribute.getValueElement() != null; + return (XmlAttributeValue)element.replace(attribute.getValueElement()); } @Override diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java index 61149c5db6ef..22c820a14f6c 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java @@ -15,13 +15,23 @@ */ package com.intellij.psi.impl.source.resolve.reference.impl.manipulators; +import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; +import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.CheckUtil; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.Factory; +import com.intellij.psi.impl.source.tree.LeafElement; +import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.xml.XmlProcessingInstruction; import com.intellij.psi.xml.XmlTokenType; +import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import static com.intellij.xml.util.documentation.HtmlDescriptorsTable.LOG; + /** * User: anna * Date: 2/20/13 @@ -30,6 +40,29 @@ public class XmlProcessingInstructionManipulator extends AbstractElementManipula @Override public XmlProcessingInstruction handleContentChange(@NotNull XmlProcessingInstruction element, @NotNull TextRange range, String newContent) throws IncorrectOperationException { - return XmlAttributeValueManipulator.handleContentChange(element, range, newContent, XmlTokenType.XML_TAG_CHARACTERS); + CheckUtil.checkWritable(element); + final CompositeElement attrNode = (CompositeElement)element.getNode(); + final ASTNode valueNode = attrNode.findLeafElementAt(range.getStartOffset()); + LOG.assertTrue(valueNode != null, "Leaf not found in " + attrNode + " at offset " + range.getStartOffset() + " in element " + element); + final PsiElement elementToReplace = valueNode.getPsi(); + + String text; + try { + text = elementToReplace.getText(); + final int offsetInParent = elementToReplace.getStartOffsetInParent(); + String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent); + String textAfterRange = text.substring(range.getEndOffset() - offsetInParent, text.length()); + newContent = element.getText().startsWith("'") || element.getText().endsWith("'") ? + newContent.replace("'", "'") : newContent.replace("\"", """); + text = textBeforeRange + newContent + textAfterRange; + } catch(StringIndexOutOfBoundsException e) { + LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e); + throw e; + } + final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(attrNode); + final LeafElement newValueElement = Factory.createSingleLeafElement(XmlTokenType.XML_TAG_CHARACTERS, text, charTableByTree, element.getManager()); + + attrNode.replaceChildInternal(valueNode, newValueElement); + return element; } } From 930eba2cc4dbb95becd2a66438037a9039190b3c Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Tue, 31 May 2016 17:04:43 +0200 Subject: [PATCH 09/35] IDEA-143263 Find In Path is not autopopulating a selection from Find Preview window --- .../intellij/usages/impl/UsagePreviewPanel.java | 15 ++++++++++++++- .../com/intellij/usages/impl/UsageViewImpl.java | 5 ++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java index 6cdc38e60b53..f323abb22c45 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsagePreviewPanel.java @@ -17,6 +17,7 @@ package com.intellij.usages.impl; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; @@ -34,6 +35,7 @@ import com.intellij.usageView.UsageViewBundle; import com.intellij.usages.UsageContextPanel; import com.intellij.usages.UsageView; import com.intellij.usages.UsageViewPresentation; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +46,7 @@ import java.util.List; /** * @author cdr */ -public class UsagePreviewPanel extends UsageContextPanelBase { +public class UsagePreviewPanel extends UsageContextPanelBase implements DataProvider { private static final Logger LOG = Logger.getInstance("#com.intellij.usages.impl.UsagePreviewPanel"); private Editor myEditor; private final boolean myIsEditor; @@ -61,6 +63,15 @@ public class UsagePreviewPanel extends UsageContextPanelBase { myIsEditor = isEditor; } + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (CommonDataKeys.EDITOR.getName().equals(dataId) && myEditor != null) { + return myEditor; + } + return null; + } + public static class Provider implements UsageContextPanel.Provider { @NotNull @Override @@ -211,6 +222,8 @@ public class UsagePreviewPanel extends UsageContextPanelBase { } } + + @Override public void updateLayoutLater(@Nullable final List infos) { if (infos == null) { diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index ad2819ecd883..26ae90a2a369 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -1572,7 +1572,10 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra VirtualFile[] data = UsageDataUtil.provideVirtualFileArray(ua, getSelectedUsageTargets()); sink.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, data); } - + else if (key == CommonDataKeys.EDITOR && myCurrentUsageContextPanel instanceof DataProvider) { + Object editor = ((DataProvider)myCurrentUsageContextPanel).getData(key.getName()); + if (editor != null) sink.put(key, editor); + } else if (key == PlatformDataKeys.HELP_ID) { sink.put(PlatformDataKeys.HELP_ID, HELP_ID); } From bacf21dec8722db2902daa063629694beadc20f8 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Tue, 31 May 2016 18:10:17 +0300 Subject: [PATCH 10/35] Refactoring: LineIndentProvider moved to lang-api, lineIndent package --- .../codeInsight/editorActions/JavaLineIndentProvider.java | 4 ++-- .../psi/codeStyle/lineIndent}/LineIndentProvider.java | 2 +- .../psi/codeStyle/lineIndent}/LineIndentProviderEP.java | 3 ++- .../psi/impl/source/codeStyle/CodeStyleFacadeImpl.java | 3 ++- .../{ => lineIndent}/FormatterBasedLineIndentProvider.java | 3 ++- .../{ => lineIndent}/JavaLikeLangLineIndentProvider.java | 5 +++-- .../platform-resources/src/META-INF/LangExtensionPoints.xml | 2 +- platform/platform-resources/src/META-INF/LangExtensions.xml | 2 +- 8 files changed, 14 insertions(+), 10 deletions(-) rename platform/{lang-impl/src/com/intellij/psi/impl/source/codeStyle => lang-api/src/com/intellij/psi/codeStyle/lineIndent}/LineIndentProvider.java (97%) rename platform/{lang-impl/src/com/intellij/psi/impl/source/codeStyle => lang-api/src/com/intellij/psi/codeStyle/lineIndent}/LineIndentProviderEP.java (92%) rename platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/{ => lineIndent}/FormatterBasedLineIndentProvider.java (92%) rename platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/{ => lineIndent}/JavaLikeLangLineIndentProvider.java (97%) diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java index feb3ad1db87c..3857da0cc18d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaLineIndentProvider.java @@ -19,14 +19,14 @@ import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; import com.intellij.psi.JavaTokenType; import com.intellij.psi.TokenType; -import com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider; +import com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider; import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition; import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider.JavaLikeElement.*; +import static com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider.JavaLikeElement.*; /** * @author Rustam Vishnyakov diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProvider.java b/platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProvider.java similarity index 97% rename from platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProvider.java rename to platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProvider.java index 78b5dcce0554..d2baf99b9cbe 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProvider.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.impl.source.codeStyle; +package com.intellij.psi.codeStyle.lineIndent; import com.intellij.lang.Language; import com.intellij.openapi.editor.Editor; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProviderEP.java b/platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProviderEP.java similarity index 92% rename from platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProviderEP.java rename to platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProviderEP.java index d1f2c9f34a0f..3b7176609b73 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/LineIndentProviderEP.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/lineIndent/LineIndentProviderEP.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.impl.source.codeStyle; +package com.intellij.psi.codeStyle.lineIndent; import com.intellij.lang.Language; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; import org.jetbrains.annotations.Nullable; /** diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java index 8473af9a7196..2ca18f1d0c7b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java @@ -27,9 +27,10 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; +import com.intellij.psi.codeStyle.lineIndent.LineIndentProviderEP; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/FormatterBasedLineIndentProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedLineIndentProvider.java similarity index 92% rename from platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/FormatterBasedLineIndentProvider.java rename to platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedLineIndentProvider.java index 7de5a996cddd..38e2812b02d5 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/FormatterBasedLineIndentProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/FormatterBasedLineIndentProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.impl.source.codeStyle; +package com.intellij.psi.impl.source.codeStyle.lineIndent; import com.intellij.lang.Language; import com.intellij.openapi.editor.Document; @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java similarity index 97% rename from platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java rename to platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java index 15c681139c0c..6974a8af543c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/JavaLikeLangLineIndentProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.psi.impl.source.codeStyle; +package com.intellij.psi.impl.source.codeStyle.lineIndent; import com.intellij.formatting.IndentInfo; import com.intellij.lang.Language; @@ -26,6 +26,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition; import com.intellij.psi.impl.source.codeStyle.SemanticEditorPosition.SyntaxElement; import com.intellij.psi.tree.IElementType; import com.intellij.util.text.CharArrayUtil; @@ -34,7 +35,7 @@ import org.jetbrains.annotations.Nullable; import static com.intellij.formatting.Indent.Type; import static com.intellij.formatting.Indent.Type.*; -import static com.intellij.psi.impl.source.codeStyle.JavaLikeLangLineIndentProvider.JavaLikeElement.*; +import static com.intellij.psi.impl.source.codeStyle.lineIndent.JavaLikeLangLineIndentProvider.JavaLikeElement.*; /** * A base class Java-like language line indent provider. If JavaLikeLangLineIndentProvider is unable to calculate diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index b1d266303395..dd2315af8b49 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -289,7 +289,7 @@ - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index b6d60fe42d55..6374f7eb25fe 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -953,7 +953,7 @@ - + From 0ccbec4a32576c2c3efffa9baed0d2e464564025 Mon Sep 17 00:00:00 2001 From: nik Date: Tue, 31 May 2016 18:20:37 +0300 Subject: [PATCH 11/35] picocontainer-related classes moved from 'util' to 'extensions' module to remove dependency on picocontainer.jar --- build/scripts/layouts.gant | 1 - .../src/com/intellij/openapi/extensions/AreaPicoContainer.java | 0 .../com/intellij/util/pico/AssignableToComponentAdapter.java | 0 .../util/pico/ConstructorInjectionComponentAdapter.java | 0 .../src/com/intellij/util/pico/DefaultPicoContainer.java | 3 ++- .../util/src/com/intellij/openapi/application/PathManager.java | 2 -- platform/util/util.iml | 1 - 7 files changed, 2 insertions(+), 5 deletions(-) rename platform/{util => extensions}/src/com/intellij/openapi/extensions/AreaPicoContainer.java (100%) rename platform/{util => extensions}/src/com/intellij/util/pico/AssignableToComponentAdapter.java (100%) rename platform/{util => extensions}/src/com/intellij/util/pico/ConstructorInjectionComponentAdapter.java (100%) rename platform/{util => extensions}/src/com/intellij/util/pico/DefaultPicoContainer.java (99%) diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 9a9e9d5409c1..3d5ae020bce0 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -952,7 +952,6 @@ def layoutJps(String home, String targetDir, String buildNumber, Closure additio include(name: "ecj*.jar") include(name: "netty-all-*.jar") include(name: "snappy-in-java-*.jar") - include(name: "picocontainer.jar") } fileset(dir: "$home/jps/lib") { include(name: "optimizedFileManager.jar") diff --git a/platform/util/src/com/intellij/openapi/extensions/AreaPicoContainer.java b/platform/extensions/src/com/intellij/openapi/extensions/AreaPicoContainer.java similarity index 100% rename from platform/util/src/com/intellij/openapi/extensions/AreaPicoContainer.java rename to platform/extensions/src/com/intellij/openapi/extensions/AreaPicoContainer.java diff --git a/platform/util/src/com/intellij/util/pico/AssignableToComponentAdapter.java b/platform/extensions/src/com/intellij/util/pico/AssignableToComponentAdapter.java similarity index 100% rename from platform/util/src/com/intellij/util/pico/AssignableToComponentAdapter.java rename to platform/extensions/src/com/intellij/util/pico/AssignableToComponentAdapter.java diff --git a/platform/util/src/com/intellij/util/pico/ConstructorInjectionComponentAdapter.java b/platform/extensions/src/com/intellij/util/pico/ConstructorInjectionComponentAdapter.java similarity index 100% rename from platform/util/src/com/intellij/util/pico/ConstructorInjectionComponentAdapter.java rename to platform/extensions/src/com/intellij/util/pico/ConstructorInjectionComponentAdapter.java diff --git a/platform/util/src/com/intellij/util/pico/DefaultPicoContainer.java b/platform/extensions/src/com/intellij/util/pico/DefaultPicoContainer.java similarity index 99% rename from platform/util/src/com/intellij/util/pico/DefaultPicoContainer.java rename to platform/extensions/src/com/intellij/util/pico/DefaultPicoContainer.java index f569c2060090..0624371db0ac 100644 --- a/platform/util/src/com/intellij/util/pico/DefaultPicoContainer.java +++ b/platform/extensions/src/com/intellij/util/pico/DefaultPicoContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.picocontainer.*; import org.picocontainer.defaults.*; +import org.picocontainer.defaults.ConstructorInjectionComponentAdapter; import java.io.Serializable; import java.util.*; diff --git a/platform/util/src/com/intellij/openapi/application/PathManager.java b/platform/util/src/com/intellij/openapi/application/PathManager.java index f76b29a37d5b..ea69e529f687 100644 --- a/platform/util/src/com/intellij/openapi/application/PathManager.java +++ b/platform/util/src/com/intellij/openapi/application/PathManager.java @@ -33,7 +33,6 @@ import org.jdom.Document; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.picocontainer.PicoContainer; import java.io.*; import java.net.URL; @@ -455,7 +454,6 @@ public class PathManager { Document.class, // jDOM Appender.class, // log4j THashSet.class, // trove4j - PicoContainer.class, // PicoContainer TypeMapper.class, // JNA FileUtils.class, // JNA (jna-platform) PatternMatcher.class, // OROMatcher diff --git a/platform/util/util.iml b/platform/util/util.iml index 6a9a8e8049f5..e5314d8d8076 100644 --- a/platform/util/util.iml +++ b/platform/util/util.iml @@ -15,7 +15,6 @@ - From 8ba4d459c29644f45da51a9687217f432019a239 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 31 May 2016 18:24:10 +0300 Subject: [PATCH 12/35] Cleanup (formatting) --- .../daemon/impl/DefaultHighlightVisitor.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java index 029a920ded25..30e98eb10319 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java @@ -47,18 +47,22 @@ class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { private final DumbService myDumbService; private HighlightInfoHolder myHolder; private final boolean myBatchMode; - private final CachedAnnotators cachedAnnotators; + private final CachedAnnotators myCachedAnnotators; @SuppressWarnings("UnusedDeclaration") DefaultHighlightVisitor(@NotNull Project project, @NotNull CachedAnnotators cachedAnnotators) { this(project, true, true, false, cachedAnnotators); } - DefaultHighlightVisitor(@NotNull Project project, boolean highlightErrorElements, boolean runAnnotators, boolean batchMode, @NotNull CachedAnnotators cachedAnnotators) { + DefaultHighlightVisitor(@NotNull Project project, + boolean highlightErrorElements, + boolean runAnnotators, + boolean batchMode, + @NotNull CachedAnnotators cachedAnnotators) { myProject = project; myHighlightErrorElements = highlightErrorElements; myRunAnnotators = runAnnotators; - this.cachedAnnotators = cachedAnnotators; + myCachedAnnotators = cachedAnnotators; myErrorFilters = Extensions.getExtensions(HighlightErrorFilter.EP_NAME, project); myDumbService = DumbService.getInstance(project); myBatchMode = batchMode; @@ -117,7 +121,7 @@ class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { @Override @NotNull public HighlightVisitor clone() { - return new DefaultHighlightVisitor(myProject, myHighlightErrorElements, myRunAnnotators, myBatchMode,cachedAnnotators); + return new DefaultHighlightVisitor(myProject, myHighlightErrorElements, myRunAnnotators, myBatchMode, myCachedAnnotators); } @Override @@ -126,7 +130,7 @@ class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { } private void runAnnotators(PsiElement element) { - List annotators = cachedAnnotators.get(element.getLanguage().getID()); + List annotators = myCachedAnnotators.get(element.getLanguage().getID()); if (annotators.isEmpty()) return; final boolean dumb = myDumbService.isDumb(); @@ -203,4 +207,4 @@ class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { } return info; } -} +} \ No newline at end of file From 71eb23037d5a2f5c9c59f283d9d9a807880f2592 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 31 May 2016 18:31:18 +0300 Subject: [PATCH 13/35] [platform] illegal character highlighting restricted to Java (IDEA-CR-10947, IDEA-156731) --- .../impl/analysis/HighlightVisitorImpl.java | 2 + .../daemon/impl/DefaultHighlightUtil.java | 39 +++++++++++++++++++ .../daemon/impl/DefaultHighlightVisitor.java | 15 ++----- 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightUtil.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index fbe7e5e82f5a..368c0ac201ce 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -220,6 +220,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } catch (IndexNotReadyException ignored) { } } + + myHolder.add(DefaultHighlightUtil.checkBadCharacter(element)); } @Override diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightUtil.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightUtil.java new file mode 100644 index 000000000000..23115b9fb39b --- /dev/null +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightUtil.java @@ -0,0 +1,39 @@ +/* + * 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. + */ +package com.intellij.codeInsight.daemon.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.TokenType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DefaultHighlightUtil { + @Nullable + public static HighlightInfo checkBadCharacter(@NotNull PsiElement element) { + ASTNode node = element.getNode(); + if (node != null && node.getElementType() == TokenType.BAD_CHARACTER) { + char c = element.textToCharArray()[0]; + boolean printable = StringUtil.isPrintableUnicode(c) && !Character.isSpaceChar(c); + String hex = String.format("U+%04X", (int)c); + String text = "Illegal character: " + (printable ? c + " (" + hex + ")" : hex); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(text).create(); + } + + return null; + } +} \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java index 30e98eb10319..d13095f4c1ad 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/DefaultHighlightVisitor.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.impl.analysis.ErrorQuickFixProvider; import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; import com.intellij.codeInsight.highlighting.HighlightErrorFilter; -import com.intellij.lang.ASTNode; import com.intellij.lang.LanguageUtil; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.Annotator; @@ -29,7 +28,10 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.*; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -97,15 +99,6 @@ class DefaultHighlightVisitor implements HighlightVisitor, DumbAware { if (myHighlightErrorElements) visitErrorElement((PsiErrorElement)element); } else { - ASTNode node = element.getNode(); - if (node != null && node.getElementType() == TokenType.BAD_CHARACTER) { - char c = element.textToCharArray()[0]; - boolean printable = StringUtil.isPrintableUnicode(c) && !Character.isSpaceChar(c); - String hex = String.format("U+%04X", (int)c); - String text = "Illegal character: " + (printable ? c + " (" + hex + ")" : hex); - myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(text).create()); - } - if (myRunAnnotators) runAnnotators(element); } From a68cb4dfd3c76d6393dee99ea5114d7485e9d4fa Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 31 May 2016 12:49:42 +0300 Subject: [PATCH 14/35] disable conversion from anonymous if method has javadoc --- .../AnonymousCanBeLambdaInspection.java | 1 + ...onymousCanBeMethodReferenceInspection.java | 48 ++++++++++++++----- .../anonymous2lambda/beforeMethodJavadoc.java | 13 +++++ .../afterComments.java | 13 +++++ .../beforeComments.java | 18 +++++++ 5 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeMethodJavadoc.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/afterComments.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/beforeComments.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 743e5d2bd7de..bdc1273196fb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -220,6 +220,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection aClass.getInitializers().length == 0) { final PsiMethod method = methods[0]; return method.getBody() != null && + method.getDocComment() == null && !hasForbiddenRefsInsideBody(method, aClass) && !hasRuntimeAnnotations(method, ignoredRuntimeAnnotations) && !method.hasModifierProperty(PsiModifier.SYNCHRONIZED); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java index f5b95d7b41d7..f72106cf8b3e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeMethodReferenceInspection.java @@ -23,19 +23,22 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.RedundantCastUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.Collection; import java.util.Collections; /** * User: anna */ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalInspectionTool { - public static final Logger LOG = Logger.getInstance("#" + AnonymousCanBeMethodReferenceInspection.class.getName()); + private static final Logger LOG = Logger.getInstance("#" + AnonymousCanBeMethodReferenceInspection.class.getName()); public boolean reportNotAnnotatedInterfaces = true; @@ -132,19 +135,38 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI final String methodRefText = LambdaCanBeMethodReferenceInspection.convertToMethodReference(methods[0].getBody(), parameters, anonymousClass.getBaseClassType(), anonymousClass.getParent()); - if (methodRefText != null) { - final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText(); - final PsiExpression psiExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, anonymousClass); - - PsiElement castExpr = anonymousClass.getParent().replace(psiExpression); - if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) { - final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand(); - LOG.assertTrue(operand != null); - castExpr = castExpr.replace(operand); - } - JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr); - } + replaceWithMethodReference(project, methodRefText, anonymousClass.getBaseClassType(), anonymousClass.getParent()); } } + } + + static void replaceWithMethodReference(@NotNull Project project, + String methodRefText, + PsiType castType, + PsiElement replacementTarget) { + final Collection comments = ContainerUtil.map(PsiTreeUtil.findChildrenOfType(replacementTarget, PsiComment.class), + comment -> (PsiComment)comment.copy()); + + if (methodRefText != null) { + final String canonicalText = castType.getCanonicalText(); + final PsiExpression psiExpression = JavaPsiFacade + .getElementFactory(project).createExpressionFromText("(" + canonicalText + ")" + methodRefText, replacementTarget); + + PsiElement castExpr = replacementTarget.replace(psiExpression); + if (RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)castExpr)) { + final PsiExpression operand = ((PsiTypeCastExpression)castExpr).getOperand(); + LOG.assertTrue(operand != null); + castExpr = castExpr.replace(operand); + } + + PsiElement anchor = PsiTreeUtil.getParentOfType(castExpr, PsiStatement.class); + if (anchor == null) { + anchor = castExpr; + } + for (PsiComment comment : comments) { + anchor.getParent().addBefore(comment, anchor); + } + JavaCodeStyleManager.getInstance(project).shortenClassReferences(castExpr); } + } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeMethodJavadoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeMethodJavadoc.java new file mode 100644 index 000000000000..8c2eb8083c54 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeMethodJavadoc.java @@ -0,0 +1,13 @@ +// "Replace with lambda" "false" +class Test { + { + Runnable r = new Runnable() { + /** + * important javadoc + */ + @Override + public void run() { + } + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/afterComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/afterComments.java new file mode 100644 index 000000000000..5bedd1497aa8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/afterComments.java @@ -0,0 +1,13 @@ +// "Replace with method reference" "true" +class Test { + + private void doTest (){} + + void foo(Runnable r){} + + { + //some comment + foo (this::doTest); + } + +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/beforeComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/beforeComments.java new file mode 100644 index 000000000000..e4c8b906079a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2methodReference/beforeComments.java @@ -0,0 +1,18 @@ +// "Replace with method reference" "true" +class Test { + + private void doTest (){} + + void foo(Runnable r){} + + { + foo (new Runnable() { + @Override + public void run() { + //some comment + doTest(); + } + }); + } + +} From ebebd66c96e9538d3ea259b8551a4db960665e54 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 31 May 2016 13:02:39 +0300 Subject: [PATCH 15/35] overloaded varargs inspection: compare methods with substituted signatures to collapse generics overloads (IDEA-156844) --- .../ig/naming/OverloadedVarargsMethodInspection.java | 8 +++++++- .../naming/OverloadedVarargsMethodInspectionTest.java | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java index eab7e149ca4e..edc13b60c5a1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/naming/OverloadedVarargsMethodInspection.java @@ -17,7 +17,9 @@ package com.siyeh.ig.naming; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiSubstitutor; import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -65,7 +67,11 @@ public class OverloadedVarargsMethodInspection extends BaseInspection { final String methodName = method.getName(); final PsiMethod[] sameNameMethods = aClass.findMethodsByName(methodName, true); for (PsiMethod sameNameMethod : sameNameMethods) { - if (!MethodSignatureUtil.areSignaturesEqual(sameNameMethod, method)) { + PsiClass superClass = sameNameMethod.getContainingClass(); + PsiSubstitutor substitutor = superClass != null ? TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY) + : PsiSubstitutor.EMPTY; + if (!MethodSignatureUtil.areSignaturesEqual(sameNameMethod.getSignature(substitutor), + method.getSignature(PsiSubstitutor.EMPTY))) { registerMethodError(method, method); return; } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java index 7fdd2709e3b2..5a8aebe72043 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/naming/OverloadedVarargsMethodInspectionTest.java @@ -55,4 +55,14 @@ public class OverloadedVarargsMethodInspectionTest extends LightInspectionTestCa " public void test(String... ss) {}" + "}"); } + + public void testGenericMethods() throws Exception { + doTest("interface Foo {" + + " void makeItSo(T command, int... values);" + + " }" + + " class Bar implements Foo {" + + " public void makeItSo(final String command, final int... values) {" + + " }" + + " }"); + } } From 11b9b229fb17e9d8e2ad71e38180d6c5e09aef04 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 31 May 2016 13:33:22 +0300 Subject: [PATCH 16/35] copy classes: skip option should proceed with the next class to copy (IDEA-156807) --- .../com/intellij/refactoring/copy/CopyClassesHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index 47e70cd0b247..ed2ddf2f8abe 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -337,7 +337,13 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase { final PsiClass[] sources = entry.getValue(); if (psiFile instanceof PsiClassOwner && sources != null) { final PsiFile createdFile = copy(psiFile, targetDirectory, copyClassName, map == null ? null : map.get(psiFile), choice); - if (createdFile == null) return null; + if (createdFile == null) { + //do not touch unmodified classes + for (PsiClass aClass : ((PsiClassOwner)psiFile).getClasses()) { + oldToNewMap.remove(aClass); + } + continue; + } for (final PsiClass destination : ((PsiClassOwner)createdFile).getClasses()) { if (isSynthetic(destination)) { continue; From 39d8047865b309b74c4f981929447b31fe50b28d Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 31 May 2016 16:42:29 +0300 Subject: [PATCH 17/35] junit fork: allow to fork per repeat (IDEA-156701) --- .../rt/execution/junit/RepeatCount.java | 0 .../testFrameworks/ForkedSplitter.java | 8 +++++- .../execution/junit/JUnitConfiguration.java | 1 + .../intellij/execution/junit/TestClass.java | 9 +++++++ .../configuration/JUnitConfigurable.java | 26 ++++++++++++++----- 5 files changed, 37 insertions(+), 7 deletions(-) rename {plugins/junit_rt => java/java-runtime}/src/com/intellij/rt/execution/junit/RepeatCount.java (100%) diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/RepeatCount.java b/java/java-runtime/src/com/intellij/rt/execution/junit/RepeatCount.java similarity index 100% rename from plugins/junit_rt/src/com/intellij/rt/execution/junit/RepeatCount.java rename to java/java-runtime/src/com/intellij/rt/execution/junit/RepeatCount.java diff --git a/java/java-runtime/src/com/intellij/rt/execution/testFrameworks/ForkedSplitter.java b/java/java-runtime/src/com/intellij/rt/execution/testFrameworks/ForkedSplitter.java index 3b9b8b282f78..3e124dd2d4d8 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/testFrameworks/ForkedSplitter.java +++ b/java/java-runtime/src/com/intellij/rt/execution/testFrameworks/ForkedSplitter.java @@ -15,6 +15,8 @@ */ package com.intellij.rt.execution.testFrameworks; +import com.intellij.rt.execution.junit.RepeatCount; + import java.io.File; import java.io.IOException; import java.io.PrintStream; @@ -39,9 +41,13 @@ public abstract class ForkedSplitter extends ForkedByModuleSplitter { } sendTree(myRootDescription); if (myWorkingDirsPath == null || new File(myWorkingDirsPath).length() == 0) { + final String classpath = System.getProperty("java.class.path"); + if (RepeatCount.getCount(repeatCount) != 0 && myForkMode.equals("repeat")) { + return startChildFork(createChildArgs(myRootDescription), null, classpath, repeatCount); + } final List children = getChildren(myRootDescription); final boolean forkTillMethod = myForkMode.equalsIgnoreCase("method"); - return splitChildren(children, 0, forkTillMethod, null, System.getProperty("java.class.path"), repeatCount); + return splitChildren(children, 0, forkTillMethod, null, classpath, repeatCount); } else { return splitPerModule(repeatCount); diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java index 607e247b2eb1..801966a3cb05 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java @@ -63,6 +63,7 @@ public class JUnitConfiguration extends JavaTestConfigurationBase { @NonNls public static final String FORK_NONE = "none"; @NonNls public static final String FORK_METHOD = "method"; @NonNls public static final String FORK_KLASS = "class"; + @NonNls public static final String FORK_REPEAT = "repeat"; // See #26522 @NonNls public static final String JUNIT_START_CLASS = "com.intellij.rt.execution.junit.JUnitStarter"; @NonNls private static final String PATTERN_EL_NAME = "pattern"; diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClass.java b/plugins/junit/src/com/intellij/execution/junit/TestClass.java index c3d0d142646d..1ce6428519dc 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClass.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClass.java @@ -20,10 +20,12 @@ import com.intellij.execution.ExecutionBundle; import com.intellij.execution.ExecutionException; import com.intellij.execution.JavaExecutionUtil; import com.intellij.execution.configurations.*; +import com.intellij.execution.junit2.configuration.JUnitConfigurationModel; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.refactoring.listeners.RefactoringElementListener; +import org.jetbrains.annotations.NotNull; class TestClass extends TestObject { public TestClass(JUnitConfiguration configuration, ExecutionEnvironment environment) { @@ -38,6 +40,13 @@ class TestClass extends TestObject { return javaParameters; } + @NotNull + @Override + protected String getForkMode() { + String forkMode = super.getForkMode(); + return JUnitConfiguration.FORK_KLASS.equals(forkMode) ? JUnitConfiguration.FORK_REPEAT : forkMode; + } + @Override public String suggestActionName() { String name = getConfiguration().getPersistentData().MAIN_CLASS_NAME; diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java index 3bf98f3732c8..9fea8e0fcf64 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java @@ -233,7 +233,16 @@ public class JUnitConfigurable extends SettingsEdi } } ); - myModel.setType(JUnitConfigurationModel.CLASS); + + myRepeatCb.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if ((Integer) myTypeChooser.getSelectedItem() == JUnitConfigurationModel.CLASS) { + myForkCb.setModel(getForkModelBasedOnRepeat()); + } + } + }); + //myModel.setType(JUnitConfigurationModel.CLASS); installDocuments(); addRadioButtonsListeners(new JRadioButton[]{myWholeProjectScope, mySingleModuleScope, myModuleWDScope}, null); myWholeProjectScope.addChangeListener(new ChangeListener() { @@ -286,6 +295,11 @@ public class JUnitConfigurable extends SettingsEdi } public void resetEditorFrom(final JUnitConfiguration configuration) { + final int count = configuration.getRepeatCount(); + myRepeatCountField.setText(String.valueOf(count)); + myRepeatCountField.setEnabled(count > 1); + myRepeatCb.setSelectedItem(configuration.getRepeatMode()); + myModel.reset(configuration); myCommonJavaParameters.reset(configuration); getModuleSelector().reset(configuration); @@ -302,10 +316,6 @@ public class JUnitConfigurable extends SettingsEdi myJrePathEditor .setPathOrName(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled()); myForkCb.setSelectedItem(configuration.getForkMode()); - final int count = configuration.getRepeatCount(); - myRepeatCountField.setText(String.valueOf(count)); - myRepeatCountField.setEnabled(count > 1); - myRepeatCb.setSelectedItem(configuration.getRepeatMode()); } private void changePanel () { @@ -346,7 +356,7 @@ public class JUnitConfigurable extends SettingsEdi myCategory.setVisible(false); myMethod.setVisible(false); myForkCb.setEnabled(true); - myForkCb.setModel(new DefaultComboBoxModel(FORK_MODE)); + myForkCb.setModel(getForkModelBasedOnRepeat()); myForkCb.setSelectedItem(selectedItem != JUnitConfiguration.FORK_KLASS ? selectedItem : JUnitConfiguration.FORK_METHOD); } else if (selectedType == JUnitConfigurationModel.METHOD){ @@ -385,6 +395,10 @@ public class JUnitConfigurable extends SettingsEdi } } + private DefaultComboBoxModel getForkModelBasedOnRepeat() { + return new DefaultComboBoxModel(RepeatCount.ONCE.equals(myRepeatCb.getSelectedItem()) ? FORK_MODE : FORK_MODE_ALL); + } + public ModulesComboBox getModulesComponent() { return myModule.getComponent(); } From 369774220c5086af852d3e6243589219eb5a902b Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Tue, 31 May 2016 18:48:20 +0300 Subject: [PATCH 18/35] Handle indent after left parenthesis '(' --- .../codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java index 6974a8af543c..b722136fd402 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/lineIndent/JavaLikeLangLineIndentProvider.java @@ -89,6 +89,11 @@ public abstract class JavaLikeLangLineIndentProvider extends FormatterBasedLineI )) { return createIndentData(CONTINUATION, ArrayOpeningBracket); } + else if (getPosition(editor, offset).matchesRule( + position -> position.before().isAt(LeftParenthesis) + )) { + return createIndentData(CONTINUATION, LeftParenthesis); + } else if (getPosition(editor, offset).matchesRule( position -> position.before().isAt(BlockOpeningBrace) )) { From d9ffe55b354e3252e6bd24885d93bdc951354ffe Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 31 May 2016 19:42:26 +0300 Subject: [PATCH 19/35] fix minor ide class resources are loaded first --- plugins/devkit/src/run/PluginRunConfiguration.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/devkit/src/run/PluginRunConfiguration.java b/plugins/devkit/src/run/PluginRunConfiguration.java index 8e257a994817..0ab59381f666 100644 --- a/plugins/devkit/src/run/PluginRunConfiguration.java +++ b/plugins/devkit/src/run/PluginRunConfiguration.java @@ -51,6 +51,7 @@ import org.jetbrains.idea.devkit.util.DescriptorUtil; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.List; import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName; @@ -184,11 +185,20 @@ public class PluginRunConfiguration extends RunConfigurationBase implements Modu params.setJdk(usedIdeaJdk); if (fromIdeaProject) { + List suppressed = Arrays.asList("jps-plugin-system"); for (String url : usedIdeaJdk.getRootProvider().getUrls(OrderRootType.CLASSES)) { String s = StringUtil.trimEnd(VfsUtilCore.urlToPath(url), JarFileSystem.JAR_SEPARATOR); - if (s.endsWith("plugin-system")) continue; + if (s.endsWith("-ide")) continue; + if (suppressed.contains(s.substring(s.lastIndexOf('/') + 1))) continue; if (new File(toSystemDependentName(s+ "/META-INF/plugin.xml")).exists()) continue; - params.getClassPath().add(toSystemDependentName(s)); + boolean first = s.endsWith("/resources"); + if (first) { + // make sure resources/ProductivityFeaturesRegistry.xml is first + params.getClassPath().addFirst(toSystemDependentName(s)); + } + else { + params.getClassPath().add(toSystemDependentName(s)); + } } } else { From d9c65ce4ee3687babb4d59cc5670fe2e98b1dc2e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 31 May 2016 20:19:58 +0300 Subject: [PATCH 20/35] ensure functional interface is found if assigned to field in another file (IDEA-156592) --- ...aredInFileWithoutFunctionalInterfaces.java | 3 ++ .../lambda/FindFunctionalInterfaceTest.java | 37 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/findUsages/FieldDeclaredInFileWithoutFunctionalInterfaces.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/findUsages/FieldDeclaredInFileWithoutFunctionalInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/findUsages/FieldDeclaredInFileWithoutFunctionalInterfaces.java new file mode 100644 index 000000000000..e56083252085 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/findUsages/FieldDeclaredInFileWithoutFunctionalInterfaces.java @@ -0,0 +1,3 @@ +public interface I { + void m(); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java index fdccb3c34cdd..cc967135b311 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FindFunctionalInterfaceTest.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.daemon.lambda; import com.intellij.JavaTestUtil; +import com.intellij.idea.Bombed; import com.intellij.psi.*; import com.intellij.psi.impl.search.JavaFunctionalExpressionSearcher; import com.intellij.psi.search.GlobalSearchScope; @@ -26,31 +27,45 @@ import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; +import java.util.Calendar; import java.util.Collection; import java.util.function.Predicate; public class FindFunctionalInterfaceTest extends LightCodeInsightFixtureTestCase { public void testMethodArgument() throws Exception { - myFixture.configureByFile(getTestName(false) + ".java"); - final PsiElement elementAtCaret = myFixture.getElementAtCaret(); - assertNotNull(elementAtCaret); - final PsiClass psiClass = PsiTreeUtil.getParentOfType(elementAtCaret, PsiClass.class, false); - assertTrue(psiClass != null && psiClass.isInterface()); - final Collection expressions = FunctionalExpressionSearch.search(psiClass).findAll(); - assertTrue(expressions.size() == 1); - final PsiFunctionalExpression next = expressions.iterator().next(); - assertNotNull(next); - assertEquals("() -> {}", next.getText()); + doTestOneExpression(); } public void testMethodArgumentByTypeParameter() throws Exception { + doTestOneExpression(); + } + + @Bombed(month = Calendar.AUGUST, day = 1, user = "ann peter") + public void testFieldDeclaredInFileWithoutFunctionalInterfaces() throws Exception { + myFixture.addClass("class B {" + + " void f(A a) {" + + " a.r = () -> {};" + + " }" + + "}"); + myFixture.addClass("public class A {" + + " public I r;" + + "}"); + for (int i = 0; i < JavaFunctionalExpressionSearcher.SMART_SEARCH_THRESHOLD + 1; i++) { + myFixture.addClass("class B" + i + " { {Runnable r = () -> {};}}"); //ensure common case is used + } + + doTestOneExpression(); + } + + private void doTestOneExpression() { myFixture.configureByFile(getTestName(false) + ".java"); final PsiElement elementAtCaret = myFixture.getElementAtCaret(); assertNotNull(elementAtCaret); final PsiClass psiClass = PsiTreeUtil.getParentOfType(elementAtCaret, PsiClass.class, false); assertTrue(psiClass != null && psiClass.isInterface()); final Collection expressions = FunctionalExpressionSearch.search(psiClass).findAll(); - assertTrue(expressions.size() == 1); + int size = expressions.size(); + assertEquals(1, size); final PsiFunctionalExpression next = expressions.iterator().next(); assertNotNull(next); assertEquals("() -> {}", next.getText()); From 0f1c211071ab98d98a3f2397e20f8fac778d6492 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Tue, 31 May 2016 20:52:09 +0300 Subject: [PATCH 21/35] move exclusions to IdeaJdk so that test runner can benefit from them --- .../src/com/intellij/openapi/util/io/FileUtil.java | 4 ++++ plugins/devkit/src/projectRoots/IdeaJdk.java | 9 ++++++++- plugins/devkit/src/run/PluginRunConfiguration.java | 14 +------------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index a17feb37587e..e6235c2a36d7 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -98,6 +98,10 @@ public class FileUtil extends FileUtilRt { return new File(path).isAbsolute(); } + public static boolean exists(@Nullable String path) { + return path != null && new File(path).exists(); + } + /** * Check if the {@code ancestor} is an ancestor of {@code file}. * diff --git a/plugins/devkit/src/projectRoots/IdeaJdk.java b/plugins/devkit/src/projectRoots/IdeaJdk.java index 04fe622e1354..14891d00d147 100644 --- a/plugins/devkit/src/projectRoots/IdeaJdk.java +++ b/plugins/devkit/src/projectRoots/IdeaJdk.java @@ -51,6 +51,8 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName; + /** * @author anna * @since Nov 22, 2004 @@ -325,8 +327,13 @@ public class IdeaJdk extends JavaDependentSdkType implements JavaSdkType { LocalFileSystem localFileSystem = LocalFileSystem.getInstance(); VirtualFile out = localFileSystem.refreshAndFindFileByPath(sdkHome + OUT_CLASSES); if (out != null) { - for (VirtualFile dir : out.getChildren()) { + List suppressed = Arrays.asList("jps-plugin-system"); + for (VirtualFile dir : JBIterable.of(out.findChild("resources")).append(out.getChildren())) { if (!dir.isDirectory()) continue; + String name = dir.getName(); + if (name.endsWith("-ide") || suppressed.contains(name)) continue; + if (!name.equals("ultimate-resources") && + FileUtil.exists(toSystemDependentName(dir.getPath() + "/META-INF/plugin.xml"))) continue; sdkModificator.addRoot(dir, OrderRootType.CLASSES); } } diff --git a/plugins/devkit/src/run/PluginRunConfiguration.java b/plugins/devkit/src/run/PluginRunConfiguration.java index 0ab59381f666..d9bdc0ad0c40 100644 --- a/plugins/devkit/src/run/PluginRunConfiguration.java +++ b/plugins/devkit/src/run/PluginRunConfiguration.java @@ -51,7 +51,6 @@ import org.jetbrains.idea.devkit.util.DescriptorUtil; import java.io.File; import java.io.IOException; import java.util.Arrays; -import java.util.List; import static com.intellij.openapi.util.io.FileUtil.toSystemDependentName; @@ -185,20 +184,9 @@ public class PluginRunConfiguration extends RunConfigurationBase implements Modu params.setJdk(usedIdeaJdk); if (fromIdeaProject) { - List suppressed = Arrays.asList("jps-plugin-system"); for (String url : usedIdeaJdk.getRootProvider().getUrls(OrderRootType.CLASSES)) { String s = StringUtil.trimEnd(VfsUtilCore.urlToPath(url), JarFileSystem.JAR_SEPARATOR); - if (s.endsWith("-ide")) continue; - if (suppressed.contains(s.substring(s.lastIndexOf('/') + 1))) continue; - if (new File(toSystemDependentName(s+ "/META-INF/plugin.xml")).exists()) continue; - boolean first = s.endsWith("/resources"); - if (first) { - // make sure resources/ProductivityFeaturesRegistry.xml is first - params.getClassPath().addFirst(toSystemDependentName(s)); - } - else { - params.getClassPath().add(toSystemDependentName(s)); - } + params.getClassPath().add(toSystemDependentName(s)); } } else { From fbc75d85589d96a9c3157a0f62449f785c451fba Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 14:57:44 +0200 Subject: [PATCH 22/35] win10: remove bold from default buttons --- .../ide/ui/laf/darcula/ui/DarculaButtonUI.java | 14 ++++++++++---- .../ide/ui/laf/intellij/WinIntelliJButtonUI.java | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java index 5abe61cefbda..a4c18667b0cb 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java @@ -162,13 +162,19 @@ public class DarculaButtonUI extends BasicButtonUI { @Override public void update(Graphics g, JComponent c) { super.update(g, c); - if (isDefaultButton(c) && !SystemInfo.isMac) { - if (!c.getFont().isBold()) { - c.setFont(new FontUIResource(c.getFont().deriveFont(Font.BOLD))); + if (isDefaultButton(c)) { + setupDefaultButton((JButton)c); + } + } + + protected void setupDefaultButton(JButton button) { + if (!SystemInfo.isMac) { + if (!button.getFont().isBold()) { + button.setFont(new FontUIResource(button.getFont().deriveFont(Font.BOLD))); } } } - + public static boolean isHelpButton(JComponent button) { return (SystemInfo.isMac || (SystemInfo.isWindows && Registry.is("ide.intellij.laf.win10.ui"))) && button instanceof JButton diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonUI.java index 98d2718ee8d9..7ac4613cc805 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonUI.java @@ -74,6 +74,11 @@ public class WinIntelliJButtonUI extends DarculaButtonUI { return true; } + @Override + protected void setupDefaultButton(JButton button) { + //do nothing + } + @Override protected void paintDisabledText(Graphics g, String text, JComponent c, Rectangle textRect, FontMetrics metrics) { g.setColor(UIManager.getColor("Button.disabledText")); From 6dc7f3f43a5a4a10f0b9ff91d45511241cdd1b89 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 20:21:51 +0200 Subject: [PATCH 23/35] cleanup --- .../intellij/WinIntelliJButtonPainter.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java index 43592a33e577..72cf7a73989a 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java @@ -35,15 +35,9 @@ public class WinIntelliJButtonPainter implements Border, UIResource { @Override public void paintBorder(Component c, Graphics graphics, int x, int y, int width, int height) { Graphics2D g = (Graphics2D)graphics; - final Insets ins = getBorderInsets(c); - final int yOff = (ins.top + ins.bottom) / 4; - final boolean square = DarculaButtonUI.isSquare(c); - int offset = JBUI.scale(square ? 1 : getOffset()); - int w = c.getWidth(); - int h = c.getHeight(); - int diam = JBUI.scale(22); - - if (c.hasFocus() || DarculaButtonUI.isDefaultButton((JComponent)c)) { + final boolean hasFocus = c.hasFocus(); + final boolean isDefault = DarculaButtonUI.isDefaultButton((JComponent)c); + if (hasFocus || isDefault) { if (DarculaButtonUI.isHelpButton((JComponent)c)) { //todo } else { @@ -52,7 +46,7 @@ public class WinIntelliJButtonPainter implements Border, UIResource { g.translate(x,y); g.drawRect(JBUI.scale(1), JBUI.scale(1), width-2*JBUI.scale(1), height-2*JBUI.scale(1)); - if (c.hasFocus()) { + if (hasFocus) { g.setStroke(new BasicStroke(JBUI.scale(1f))); g.setColor(Gray.x00); UIUtil.drawDottedRectangle(g, JBUI.scale(1) + 1, JBUI.scale(1) + 1, width-2*JBUI.scale(1) - 1, height-2*JBUI.scale(1) - 1); @@ -72,12 +66,12 @@ public class WinIntelliJButtonPainter implements Border, UIResource { @Override public Insets getBorderInsets(Component c) { if (c.getParent() instanceof ActionToolbar) { - return JBUI.insets(4, 16, 4, 16); + return JBUI.insets(4, 16).asUIResource(); } if (DarculaButtonUI.isSquare(c)) { - return JBUI.insets(2, 0, 2, 0).asUIResource(); + return JBUI.insets(2, 0).asUIResource(); } - return JBUI.insets(3, 17, 3, 15).asUIResource(); + return JBUI.insets(3, 17).asUIResource(); } protected int getOffset() { From 83824d2ab662391682fd838240e8d0498103be2e Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 21:44:50 +0200 Subject: [PATCH 24/35] customize one pixel divider bg --- .../src/com/intellij/openapi/ui/OnePixelDivider.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java b/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java index d92d97b001b9..1312dabe6064 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/OnePixelDivider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * 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. @@ -36,7 +36,10 @@ import java.awt.event.MouseEvent; * @author Konstantin Bulenkov */ public class OnePixelDivider extends Divider { - public static final Color BACKGROUND = new JBColor(Gray.xC5, Gray.x51); + public static final Color BACKGROUND = new JBColor(() -> { + final Color bg = UIManager.getColor("OnePixelDivider.background"); + return bg != null ? bg : new JBColor(Gray.xC5, Gray.x51); + }); private boolean myVertical; private Splittable mySplitter; From 3979a8421b8735a3807d2c59e734c9c6d26764fc Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 21:45:18 +0200 Subject: [PATCH 25/35] make win10 checkbox smaller --- .../intellij/ide/ui/laf/intellij/WinIntelliJCheckBoxUI.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJCheckBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJCheckBoxUI.java index e5e7272a8dc1..8bbe1c252804 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJCheckBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJCheckBoxUI.java @@ -67,4 +67,9 @@ public class WinIntelliJCheckBoxUI extends IntelliJCheckBoxUI { UIUtil.drawDottedRectangle(g, textRect.x - 2, textRect.y - 1, textRect.width + textRect.x + 1, textRect.height + 3); } } + + @Override + public Icon getDefaultIcon() { + return JBUI.emptyIcon(18).asUIResource(); + } } From 2a757f30c11a064eaf396ef08b514457d6b0ddca Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 21:46:21 +0200 Subject: [PATCH 26/35] leave only one opaque panel for buttons in south panel in DialogWrapper --- .../com/intellij/openapi/ui/DialogWrapper.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 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 11d2b26b95be..ce40c9c714c5 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java @@ -44,6 +44,7 @@ import com.intellij.ui.UIBundle; import com.intellij.ui.border.CustomLineBorder; import com.intellij.ui.components.JBOptionButton; import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.util.Alarm; import com.intellij.util.ArrayUtil; import com.intellij.util.TimeoutUtil; @@ -468,8 +469,15 @@ public abstract class DialogWrapper { actions = ArrayUtil.remove(actions, getHelpAction()); } - JPanel panel = new JPanel(new BorderLayout()); - final JPanel lrButtonsPanel = new JPanel(new GridBagLayout()); + JPanel panel = new JPanel(new BorderLayout()) { + @Override + public Color getBackground() { + final Color bg = UIManager.getColor("DialogWrapper.southPanelBackground"); + return bg != null ? bg : super.getBackground(); + } + }; + final JPanel lrButtonsPanel = new NonOpaquePanel(new GridBagLayout()); + //noinspection UseDPIAwareInsets final Insets insets = SystemInfo.isMacOSLeopard ? UIUtil.isUnderIntelliJLaF() ? JBUI.insets(0, 8) : JBUI.emptyInsets() : new Insets(8, 0, 0, 0); //don't wrap to JBInsets if (actions.length > 0 || leftSideActions.length > 0) { @@ -551,12 +559,12 @@ public abstract class DialogWrapper { } if (getStyle() == DialogStyle.COMPACT) { - Border line = new CustomLineBorder(OnePixelDivider.BACKGROUND, 1, 0, 0, 0); + final Color color = UIManager.getColor("DialogWrapper.southPanelDivider"); + Border line = new CustomLineBorder(color != null ? color : OnePixelDivider.BACKGROUND, 1, 0, 0, 0); panel.setBorder(new CompoundBorder(line, JBUI.Borders.empty(8, 12))); } else { panel.setBorder(JBUI.Borders.emptyTop(8)); } - return panel; } @@ -636,7 +644,7 @@ public abstract class DialogWrapper { } } - JPanel buttonsPanel = new JPanel(new GridLayout(1, actions.length, SystemInfo.isMacOSLeopard ? UIUtil.isUnderIntelliJLaF() ? 8 : 0 : 5, 0)); + JPanel buttonsPanel = new NonOpaquePanel(new GridLayout(1, actions.length, SystemInfo.isMacOSLeopard ? UIUtil.isUnderIntelliJLaF() ? 8 : 0 : 5, 0)); for (final Action action : actions) { JButton button = createJButtonForAction(action); final Object value = action.getValue(Action.MNEMONIC_KEY); From 17bfb6efa0fe553a50b1e3c7bb32dca990a1d0fe Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 31 May 2016 21:47:24 +0200 Subject: [PATCH 27/35] win10: customize buttons and separators in dialog wrapper --- .../src/com/intellij/ide/ui/laf/intellijlaf_native.properties | 3 +++ 1 file changed, 3 insertions(+) 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 d7e706395cd6..dcc1e3710cd0 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 @@ -18,6 +18,9 @@ textInactiveText=999999 textText=000000 infoText=000000 OptionPane.messageForeground=000000 +DialogWrapper.southPanelDivider=f0f0f0 +DialogWrapper.southPanelBackground=f0f0f0 +OnePixelDivider.background=ffffff Menu.maxGutterIconWidth=18 MenuItem.maxGutterIconWidth=18 From 393e26092c08ee6d4bf0361a3dbb1a66cc7514ef Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Tue, 31 May 2016 23:02:13 +0300 Subject: [PATCH 28/35] [vcs-log] enable background refresh and toolbar progress --- platform/util/resources/misc/registry.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index f7ac6808e474..50b263a9ba16 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -268,7 +268,7 @@ vcs.log.recent.commits.count=1000 vcs.log.recent.commits.count.description=Before full log is loaded (which can take some time), a number of recent commits is loaded to show quickly vcs.log.open.another.log.visible=false vcs.log.open.another.log.visible.description=An action that opens a new tab with log -vcs.log.keep.up.to.date=false +vcs.log.keep.up.to.date=true vcs.log.keep.up.to.date.description=Load log on start after heavy tasks are completed and keep it up to date even when not visible vcs.executable.validator.timeout.sec=60 From 58b79f1997d6c77356643ff00a5190b14848d9c5 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 31 May 2016 23:08:53 +0300 Subject: [PATCH 29/35] IDEA-156869 HintManagerImpl#myLastEditor leaks project --- .../src/com/intellij/codeInsight/hint/HintManagerImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java index b1a453727bd7..33815d491c1d 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintManagerImpl.java @@ -949,6 +949,9 @@ public class HintManagerImpl extends HintManager implements Disposable { myQuestionAction = null; myQuestionHint = null; + if (myLastEditor != null && project == myLastEditor.getProject()) { + updateLastEditor(null); + } } } From 055712a7a1f50009abaac63ce06dd9397cfb501b Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 31 May 2016 23:08:05 +0300 Subject: [PATCH 30/35] Removing invalid element from PythonPathCache to prevent PSIAE --- .../python/psi/resolve/PythonPathCache.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java b/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java index 87a402df3f67..2ff1e388c903 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java +++ b/python/src/com/jetbrains/python/psi/resolve/PythonPathCache.java @@ -15,12 +15,15 @@ */ package com.jetbrains.python.psi.resolve; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.*; import com.intellij.psi.PsiElement; import com.intellij.psi.util.QualifiedName; -import com.intellij.util.containers.ConcurrentHashMap; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -28,28 +31,37 @@ import java.util.Map; * @author yole */ public abstract class PythonPathCache { - private final Map> myCache = new ConcurrentHashMap>(); - private final Map> myQNameCache = new ConcurrentHashMap>(); + private final Map> myCache = ContainerUtil.newConcurrentMap(); + private final Map> myQNameCache = ContainerUtil.newConcurrentMap(); public void clearCache() { myCache.clear(); myQNameCache.clear(); } + @Nullable public List get(QualifiedName qualifiedName) { - return myCache.get(qualifiedName); + final List result = myCache.get(qualifiedName); + if (result == null) { + return null; + } + final boolean staleElementRemoved = result.removeIf(e -> !e.isValid()); + if (staleElementRemoved) { + Logger.getInstance(PythonPathCache.class).warn("Removing invalid element from cache"); + } + return (!result.isEmpty() ? result : null); } public void put(QualifiedName qualifiedName, List results) { - myCache.put(qualifiedName, results); + myCache.put(qualifiedName, new ArrayList<>(results)); } public List getNames(VirtualFile vFile) { return myQNameCache.get(vFile); } - + public void putNames(VirtualFile vFile, List qNames) { - myQNameCache.put(vFile, qNames); + myQNameCache.put(vFile, new ArrayList<>(qNames)); } protected class MyVirtualFileAdapter extends VirtualFileAdapter { From 85eeec1a7ed44e3a0d7bb8ef07e8db686c369ad0 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 1 Jun 2016 00:37:43 +0300 Subject: [PATCH 31/35] Revert "handle values containing multiple tokens" This reverts commit 1bcb4977835f36e22aa9d6fbae931b6a30c748ec. --- .../XmlAttributeValueManipulator.java | 45 ++++++++++++------- .../XmlProcessingInstructionManipulator.java | 35 +-------------- 2 files changed, 31 insertions(+), 49 deletions(-) diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java index f41d1d30ec63..efb0a79862fb 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java @@ -20,12 +20,15 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; import com.intellij.psi.PsiElement; -import com.intellij.psi.XmlElementFactory; import com.intellij.psi.impl.CheckUtil; -import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.Factory; +import com.intellij.psi.impl.source.tree.LeafElement; +import com.intellij.psi.impl.source.tree.SharedImplUtil; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.xml.XmlAttributeValue; -import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlTokenType; +import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -41,25 +44,37 @@ public class XmlAttributeValueManipulator extends AbstractElementManipulator T handleContentChange(T element, + TextRange range, + String newContent, + final IElementType tokenType) { CheckUtil.checkWritable(element); + final CompositeElement attrNode = (CompositeElement)element.getNode(); + final ASTNode valueNode = attrNode.findLeafElementAt(range.getStartOffset()); + LOG.assertTrue(valueNode != null, "Leaf not found in " + attrNode + " at offset " + range.getStartOffset() + " in element " + element); + final PsiElement elementToReplace = valueNode.getPsi(); String text; - final String oldText = element.getText(); try { - String textBeforeRange = oldText.substring(0, range.getStartOffset()); - String textAfterRange = oldText.substring(range.getEndOffset(), oldText.length()); - newContent = oldText.startsWith("'") || oldText.endsWith("'") ? - newContent.replace("'", oldText.contains("'") ? "'" : "'") : - newContent.replace("\"", oldText.contains(""") ? """ : """); - text = ""; + text = elementToReplace.getText(); + final int offsetInParent = elementToReplace.getStartOffsetInParent(); + String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent); + String textAfterRange = text.substring(range.getEndOffset()- offsetInParent, text.length()); + newContent = element.getText().startsWith("'") || element.getText().endsWith("'") ? + newContent.replace("'", "'") : newContent.replace("\"", """); + text = textBeforeRange + newContent + textAfterRange; } catch(StringIndexOutOfBoundsException e) { - LOG.error("Range: " + range + " in text: '" + oldText + "'", e); + LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e); throw e; } - final XmlTag tag = XmlElementFactory.getInstance(element.getProject()).createTagFromText(text); - final XmlAttribute attribute = tag.getAttribute("value"); - assert attribute != null && attribute.getValueElement() != null; - return (XmlAttributeValue)element.replace(attribute.getValueElement()); + final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(attrNode); + final LeafElement newValueElement = Factory.createSingleLeafElement(tokenType, text, charTableByTree, element.getManager()); + + attrNode.replaceChildInternal(valueNode, newValueElement); + return element; } @Override diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java index 22c820a14f6c..61149c5db6ef 100644 --- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java +++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlProcessingInstructionManipulator.java @@ -15,23 +15,13 @@ */ package com.intellij.psi.impl.source.resolve.reference.impl.manipulators; -import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; -import com.intellij.psi.PsiElement; -import com.intellij.psi.impl.CheckUtil; -import com.intellij.psi.impl.source.tree.CompositeElement; -import com.intellij.psi.impl.source.tree.Factory; -import com.intellij.psi.impl.source.tree.LeafElement; -import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.xml.XmlProcessingInstruction; import com.intellij.psi.xml.XmlTokenType; -import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; -import static com.intellij.xml.util.documentation.HtmlDescriptorsTable.LOG; - /** * User: anna * Date: 2/20/13 @@ -40,29 +30,6 @@ public class XmlProcessingInstructionManipulator extends AbstractElementManipula @Override public XmlProcessingInstruction handleContentChange(@NotNull XmlProcessingInstruction element, @NotNull TextRange range, String newContent) throws IncorrectOperationException { - CheckUtil.checkWritable(element); - final CompositeElement attrNode = (CompositeElement)element.getNode(); - final ASTNode valueNode = attrNode.findLeafElementAt(range.getStartOffset()); - LOG.assertTrue(valueNode != null, "Leaf not found in " + attrNode + " at offset " + range.getStartOffset() + " in element " + element); - final PsiElement elementToReplace = valueNode.getPsi(); - - String text; - try { - text = elementToReplace.getText(); - final int offsetInParent = elementToReplace.getStartOffsetInParent(); - String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent); - String textAfterRange = text.substring(range.getEndOffset() - offsetInParent, text.length()); - newContent = element.getText().startsWith("'") || element.getText().endsWith("'") ? - newContent.replace("'", "'") : newContent.replace("\"", """); - text = textBeforeRange + newContent + textAfterRange; - } catch(StringIndexOutOfBoundsException e) { - LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e); - throw e; - } - final CharTable charTableByTree = SharedImplUtil.findCharTableByTree(attrNode); - final LeafElement newValueElement = Factory.createSingleLeafElement(XmlTokenType.XML_TAG_CHARACTERS, text, charTableByTree, element.getManager()); - - attrNode.replaceChildInternal(valueNode, newValueElement); - return element; + return XmlAttributeValueManipulator.handleContentChange(element, range, newContent, XmlTokenType.XML_TAG_CHARACTERS); } } From 366e0ecbc412e0b627fdabe0e5606c4fa95f165d Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Wed, 1 Jun 2016 00:32:22 +0300 Subject: [PATCH 32/35] compensate multiple updates in a row --- .../treetable/TreeTableModelAdapter.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/treetable/TreeTableModelAdapter.java b/platform/platform-api/src/com/intellij/ui/treeStructure/treetable/TreeTableModelAdapter.java index cbca7f173ad9..6558ab3f7d2b 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/treetable/TreeTableModelAdapter.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/treetable/TreeTableModelAdapter.java @@ -22,6 +22,7 @@ import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.tree.TreePath; +import java.util.concurrent.atomic.AtomicInteger; /** * This is a wrapper class takes a TreeTableModel and implements @@ -35,6 +36,9 @@ import javax.swing.tree.TreePath; * @author Scott Violet */ public class TreeTableModelAdapter extends AbstractTableModel { + + private final AtomicInteger modificationStamp = new AtomicInteger(); + private final JTree tree; private final TreeTableModel treeTableModel; private final JTable table; @@ -123,7 +127,12 @@ public class TreeTableModelAdapter extends AbstractTableModel { * processed. SwingUtilities.invokeLater is used to handle this. */ protected void delayedFireTableDataChanged() { - SwingUtilities.invokeLater(() -> fireTableDataChanged()); + long stamp = modificationStamp.incrementAndGet(); + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> { + if (stamp != modificationStamp.get()) return; + fireTableDataChanged(); + }); } public void fireTableDataChanged() { From c4176a20ca4175e11595d650a9edf93637b77486 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 1 Jun 2016 00:42:05 +0300 Subject: [PATCH 33/35] Logging improved to catch leaked thread --- .../com/jetbrains/env/PyProcessWithConsoleTestTask.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java b/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java index bdd921d40aba..b7e9e419b228 100644 --- a/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java +++ b/python/testSrc/com/jetbrains/env/PyProcessWithConsoleTestTask.java @@ -15,12 +15,12 @@ */ package com.jetbrains.env; -import com.intellij.execution.ExecutionException; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessOutputTypes; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; @@ -53,6 +53,7 @@ import java.lang.reflect.InvocationTargetException; * @author Ilya.Kazakevich */ public abstract class PyProcessWithConsoleTestTask extends PyExecutionFixtureTestTask { + private static final Logger LOG = Logger.getInstance(PyProcessWithConsoleTestTask.class); @NotNull private final SdkCreationType myRequiredSdkType; @@ -91,6 +92,7 @@ public abstract class PyProcessWithConsoleTestTask Date: Wed, 1 Jun 2016 07:30:23 +0200 Subject: [PATCH 34/35] clean up AstPath objects when no PSI is accessed, e.g. after project closing --- .../com/intellij/psi/impl/source/AstPathPsiMap.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/AstPathPsiMap.java b/platform/core-impl/src/com/intellij/psi/impl/source/AstPathPsiMap.java index 50764706ca1e..0be43afc1577 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/AstPathPsiMap.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/AstPathPsiMap.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source; +import com.intellij.concurrency.JobScheduler; import com.intellij.extapi.psi.StubBasedPsiElementBase; import com.intellij.psi.impl.source.tree.AstPath; import com.intellij.psi.impl.source.tree.CompositeElement; @@ -26,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; /** * A weak cache for all instantiated stub-based PSI to allow {@link CompositeElement#getPsi()} return it when AST is reloaded.

@@ -39,6 +41,16 @@ class AstPathPsiMap { */ private final ConcurrentMap myMap = ContainerUtil.newConcurrentMap(); + static { + JobScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + // clean up AstPath objects when no PSI is accessed, e.g. after project closing + processQueue(); + } + }, 5, 5, TimeUnit.SECONDS); + } + void invalidatePsi() { processQueue(); for (MyReference reference : myMap.values()) { From 8a33d34159ced02725a99867e1f589ab195df991 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 1 Jun 2016 07:56:22 +0200 Subject: [PATCH 35/35] add PsiDocumentManagerImplTest.testPerformLaterWhenAllCommittedFromCommitHandler (IDEA-CR-11146) --- .../psi/impl/PsiDocumentManagerImplTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java index 221c3413d837..e311e1a04c75 100644 --- a/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/psi/impl/PsiDocumentManagerImplTest.java @@ -671,4 +671,22 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase { assertTrue(PsiDocumentManager.getInstance(myProject).isCommitted(document)); } + @SuppressWarnings("ConstantConditions") + public void testPerformLaterWhenAllCommittedFromCommitHandler() throws Exception { + PsiFile file = getPsiManager().findFile(getVirtualFile(createTempFile("X.txt", ""))); + Document document = file.getViewProvider().getDocument(); + + PsiDocumentManager pdm = PsiDocumentManager.getInstance(myProject); + WriteCommandAction.runWriteCommandAction(null, () -> document.insertString(0, "a")); + pdm.performWhenAllCommitted( + () -> pdm.performLaterWhenAllCommitted( + () -> WriteCommandAction.runWriteCommandAction(null, () -> document.insertString(1, "b")))); + + assertTrue(pdm.hasUncommitedDocuments()); + assertEquals("a", document.getText()); + + DocumentCommitThread.getInstance().waitForAllCommits(); + assertEquals("ab", document.getText()); + } + }