From 0e096c971a583261367047fa7c3e7b0f36c1b16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pap=20L=C5=91rinc?= Date: Sun, 30 Aug 2015 20:12:38 +0300 Subject: [PATCH 01/27] align chained methods with comments properly --- .../psi/formatter/java/AbstractJavaBlock.java | 6 +++--- .../java/ChainMethodCallsBlockBuilder.java | 8 +++++--- .../java/JavaFormatterAlignmentTest.java | 20 ++++++++++++++++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 25bd89226a38..c1a61a877860 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -701,9 +701,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo ASTNode child = node.getFirstChildNode(); while (child != null) { if (!FormatterUtil.containsWhiteSpacesOnly(child)) { - if (child.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION || child.getElementType() == - JavaElementType - .REFERENCE_EXPRESSION) { + IElementType type = child.getElementType(); + if (type == JavaElementType.METHOD_CALL_EXPRESSION || + type == JavaElementType.REFERENCE_EXPRESSION) { collectNodes(nodes, child); } else { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java b/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java index 799027f701b5..e5e3ed668fce 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/ChainMethodCallsBlockBuilder.java @@ -75,8 +75,10 @@ class ChainMethodCallsBlockBuilder { for (int i = 0; i < methodCall.size(); i++) { ChainedCallChunk currentCallChunk = methodCall.get(i); if (isMethodCall(currentCallChunk)) { - if (myWrap == null) myWrap = createCallChunkWrap(i, methodCall); - if (myChainedCallsAlignment == null) myChainedCallsAlignment = createCallChunkAlignment(i, methodCall); + if (myWrap == null) + myWrap = createCallChunkWrap(i, methodCall); + if (myChainedCallsAlignment == null) + myChainedCallsAlignment = createCallChunkAlignment(i, methodCall); } else { myWrap = null; @@ -137,7 +139,7 @@ class ChainMethodCallsBlockBuilder { private boolean isMethodCall(@NotNull ChainedCallChunk callChunk) { List nodes = callChunk.nodes; - return !nodes.isEmpty() && nodes.get(nodes.size() - 1).getElementType() == JavaElementType.EXPRESSION_LIST; + return nodes.size() >= 3 && nodes.get(2).getElementType() == JavaElementType.EXPRESSION_LIST; } } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java index dadf7fbf590f..11021e7c0cfd 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java @@ -49,6 +49,20 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { ); } + public void testChainedMethodWithComments() throws Exception { + getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true; + doMethodTest("AA.bb()\n" + + ".cc() // comment after line\n" + + ".dd()\n " + + " /* block comment on empty line */\n" + + ".ee();", + "AA.bb()\n" + + " .cc() // comment after line\n" + + " .dd()\n " + + "/* block comment on empty line */\n" + + " .ee();"); + } + public void testMultipleMethodAnnotationsCommentedInTheMiddle() throws Exception { getSettings().BLANK_LINES_AFTER_CLASS_HEADER = 1; getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA).INDENT_SIZE = 4; @@ -256,7 +270,7 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { "}" ); } - + public void testAnnotatedAndNonAnnotatedFieldsInColumnsAlignment() { // Inspired by IDEA-60237 @@ -281,10 +295,10 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { "}" ); } - + public void testAlignThrowsKeyword() throws Exception { // Inspired by IDEA-63820 - + getSettings().ALIGN_THROWS_KEYWORD = true; doClassTest( "public void test()\n" + From ee809c4b44972edf91977342610c1a98a1a2af6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pap=20L=C5=91rinc?= Date: Mon, 31 Aug 2015 23:06:14 +0300 Subject: [PATCH 02/27] Changed testChainedMethodWithComments to be more descriptive --- .../java/JavaFormatterAlignmentTest.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java index 11021e7c0cfd..fcadd85e9c2c 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterAlignmentTest.java @@ -51,16 +51,17 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest { public void testChainedMethodWithComments() throws Exception { getSettings().ALIGN_MULTILINE_CHAINED_METHODS = true; - doMethodTest("AA.bb()\n" + - ".cc() // comment after line\n" + - ".dd()\n " + - " /* block comment on empty line */\n" + - ".ee();", - "AA.bb()\n" + - " .cc() // comment after line\n" + - " .dd()\n " + - "/* block comment on empty line */\n" + - " .ee();"); + doMethodTest("AAAAA.b()\n" + + ".c() // comment after line\n" + + ".d()\n" + + " /* unaligned block comment on separate line */\n" + + ".e();", + + "AAAAA.b()\n" + + " .c() // comment after line\n" + + " .d()\n" + + "/* unaligned block comment on separate line */\n" + + " .e();"); } public void testMultipleMethodAnnotationsCommentedInTheMiddle() throws Exception { From cad04265043ece36983e920916021eaa4524e5aa Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 08:40:41 +0200 Subject: [PATCH 03/27] use.loaded.state.as.existing, default false until client issues are not fixed. --- platform/configuration-store-impl/src/ComponentStoreImpl.kt | 3 ++- platform/util/resources/misc/registry.properties | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index b7fca615e950..0a9d847e3b85 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util import com.intellij.openapi.util.* import com.intellij.openapi.util.Pair +import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.util.ArrayUtilRt @@ -248,7 +249,7 @@ abstract class ComponentStoreImpl : IComponentStore { } val storage = storageManager.getStateStorage(storageSpec) - var stateGetter = (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) + var stateGetter = if (Registry.`is`("use.loaded.state.as.existing", false)) (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) else null var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState) if (state == null) { if (changedStorages != null && changedStorages.contains(storage)) { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 85efd2301fbd..e68c86255fc1 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -652,6 +652,7 @@ testDiscovery.enabled=false ruby.remote.debugger.supports.catchpoint.removal=true use.read.action.to.init.service=true +use.loaded.state.as.existing=false ide.mac.new.color.picker=false From 8d5dd11cdba9a214dc541442ce71b9364d3d48e2 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 2 Sep 2015 08:47:44 +0200 Subject: [PATCH 04/27] avoid PsiVFSListener nesting (EA-56525 - assert: PsiManagerImpl.fireEvent) --- .../psi/impl/file/impl/PsiVFSListener.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java index 5a0fc06a21cb..dfd37eae7b9c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java @@ -29,10 +29,10 @@ import com.intellij.openapi.fileTypes.FileTypeListener; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter; @@ -60,6 +60,30 @@ public class PsiVFSListener extends VirtualFileAdapter { private final Project myProject; private boolean myReportedUnloadedPsiChange; + static { + ApplicationManager.getApplication().getMessageBus().connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + public void before(@NotNull List events) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + PsiVFSListener listener = project.getComponent(PsiVFSListener.class); + assert listener != null; + new BulkVirtualFileListenerAdapter(listener).before(events); + } + } + + @Override + public void after(@NotNull List events) { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + PsiVFSListener listener = project.getComponent(PsiVFSListener.class); + assert listener != null; + listener.myReportedUnloadedPsiChange = false; + new BulkVirtualFileListenerAdapter(listener).after(events); + listener.myReportedUnloadedPsiChange = false; + } + } + }); + } + public PsiVFSListener(Project project) { myProject = project; myFileTypeManager = FileTypeManager.getInstance(); @@ -72,20 +96,6 @@ public class PsiVFSListener extends VirtualFileAdapter { StartupManager.getInstance(project).registerPreStartupActivity(new Runnable() { @Override public void run() { - final BulkVirtualFileListenerAdapter adapter = new BulkVirtualFileListenerAdapter(PsiVFSListener.this); - myConnection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { - @Override - public void before(@NotNull List events) { - adapter.before(events); - } - - @Override - public void after(@NotNull List events) { - myReportedUnloadedPsiChange = false; - adapter.after(events); - myReportedUnloadedPsiChange = false; - } - }); myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new MyModuleRootListener()); myConnection.subscribe(FileTypeManager.TOPIC, new FileTypeListener.Adapter() { @Override @@ -595,11 +605,6 @@ public class PsiVFSListener extends VirtualFileAdapter { true, false); } - // When file is renamed so that extension changes then language dialect might change and thus psiFile should be invalidated - private static boolean languageDialectChanged(final PsiFile newPsiFile, String oldFileName) { - return newPsiFile != null && !FileUtilRt.extensionEquals(oldFileName, FileUtilRt.getExtension(newPsiFile.getName())); - } - private class MyModuleRootListener implements ModuleRootListener { private VirtualFile[] myOldContentRoots = null; private volatile int depthCounter = 0; From 480434deb0fdd3cec57aa5fc40ac586cd971aba7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 08:51:29 +0200 Subject: [PATCH 05/27] use.loaded.state.as.existing, default false until client issues are not fixed. --- platform/configuration-store-impl/src/XmlElementStorage.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index 67bed1a75dac..08f77b834051 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -20,6 +20,7 @@ import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.TrackingPathMacroSubstitutor import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil import com.intellij.openapi.util.JDOMUtil +import com.intellij.openapi.util.registry.Registry import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.SmartHashSet import gnu.trove.THashMap @@ -37,7 +38,9 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S protected abstract fun loadLocalData(): Element? - override final fun getState(storageData: StateMap, component: Any?, componentName: String) = storageData.getState(componentName) + override final fun getState(storageData: StateMap, component: Any?, componentName: String): Element? { + return if (Registry.`is`("use.loaded.state.as.existing", false)) storageData.getState(componentName) else storageData.getStateAndArchive(componentName) + } override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) { storageData.archive(componentName, serializedState) From 8dee8304207b9066731d16a81d015e39488b920a Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 09:56:44 +0200 Subject: [PATCH 06/27] cleanup --- .../navigator/MavenProjectsNavigator.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java index c769e6c872ca..a66c6d841dcb 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -92,6 +92,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen myShortcutsManager = shortcutsManager; } + @Override public MavenProjectsNavigatorState getState() { ApplicationManager.getApplication().assertIsDispatchThread(); if (myStructure != null) { @@ -106,6 +107,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen return myState; } + @Override public void loadState(MavenProjectsNavigatorState state) { myState = state; scheduleStructureUpdate(); @@ -183,6 +185,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen listenForProjectsChanges(); if (isUnitTestMode()) return; MavenUtil.runWhenInitialized(myProject, new DumbAwareRunnable() { + @Override public void run() { if (myProject.isDisposed()) return; initToolWindow(); @@ -200,8 +203,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen myProjectsManager.addProjectsTreeListener(new MyProjectsListener()); myShortcutsManager.addListener(new MavenShortcutsManager.Listener() { + @Override public void shortcutsUpdated() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateGoals(); } @@ -210,8 +215,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen }); myTasksManager.addListener(new MavenTasksManager.Listener() { + @Override public void compileTasksChanged() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateGoals(); } @@ -220,8 +227,10 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen }); RunManagerEx.getInstanceEx(myProject).addRunManagerListener(new RunManagerAdapter() { + @Override public void beforeRunTasksChanged() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateGoals(); } @@ -233,6 +242,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen @Override public void skipTestsChanged() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateGoals(); } @@ -243,6 +253,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen ((RunManagerEx)RunManager.getInstance(myProject)).addRunManagerListener(new RunManagerAdapter() { private void changed() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateRunConfigurations(); } @@ -291,9 +302,11 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen public void stateChanged() { if (myToolWindow.isDisposed()) return; boolean visible = myToolWindow.isVisible(); - if (!visible || visible == wasVisible) return; + if (!visible || wasVisible) { + return; + } scheduleStructureUpdate(); - wasVisible = visible; + wasVisible = true; } }; manager.addToolWindowManagerListener(listener, myProject); @@ -350,6 +363,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen public void selectInTree(final MavenProject project) { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.select(project); } @@ -364,6 +378,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen if (myToolWindow == null) return; MavenUtil.invokeLater(myProject, new Runnable() { + @Override public void run() { if (!myToolWindow.isVisible()) return; @@ -396,6 +411,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen private void scheduleStructureUpdate() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.update(); } @@ -403,10 +419,12 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen } private class MyProjectsListener extends MavenProjectsTree.ListenerAdapter implements MavenProjectsManager.Listener { + @Override public void activated() { scheduleStructureUpdate(); } + @Override public void projectsScheduled() { } @@ -417,6 +435,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen @Override public void projectsIgnoredStateChanged(final List ignored, final List unignored, boolean fromImport) { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateIgnored(ContainerUtil.concat(ignored, unignored)); } @@ -426,6 +445,7 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen @Override public void profilesChanged() { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateProfiles(); } @@ -437,17 +457,20 @@ public class MavenProjectsNavigator extends MavenSimpleProjectComponent implemen scheduleUpdateProjects(MavenUtil.collectFirsts(updated), deleted); } + @Override public void projectResolved(Pair projectWithChanges, NativeMavenProjectHolder nativeMavenProject) { scheduleUpdateProjects(Collections.singletonList(projectWithChanges.first), Collections.emptyList()); } + @Override public void pluginsResolved(MavenProject project) { scheduleUpdateProjects(Collections.singletonList(project), Collections.emptyList()); } private void scheduleUpdateProjects(final List projects, final List deleted) { scheduleStructureRequest(new Runnable() { + @Override public void run() { myStructure.updateProjects(projects, deleted); } From 1cb60fc40155e0708a64f4e554d5517be7d3c261 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 10:05:50 +0200 Subject: [PATCH 07/27] move use.loaded.state.as.existing check to correct place --- .../src/ComponentStoreImpl.kt | 10 ++-------- .../configuration-store-impl/src/StorageBaseEx.kt | 12 ++++++------ .../src/XmlElementStorage.kt | 5 +---- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index 0a9d847e3b85..be72f34d9085 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -33,7 +33,6 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util import com.intellij.openapi.util.* import com.intellij.openapi.util.Pair -import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.util.ArrayUtilRt @@ -249,7 +248,7 @@ abstract class ComponentStoreImpl : IComponentStore { } val storage = storageManager.getStateStorage(storageSpec) - var stateGetter = if (Registry.`is`("use.loaded.state.as.existing", false)) (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) else null + var stateGetter = (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState) if (state == null) { if (changedStorages != null && changedStorages.contains(storage)) { @@ -262,12 +261,7 @@ abstract class ComponentStoreImpl : IComponentStore { } } - try { - component.loadState(state) - } - finally { - stateGetter?.close() - } + stateGetter?.use { component.loadState(state) } return name } diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 94affaa5693e..217b257d5f35 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -15,9 +15,12 @@ */ package com.intellij.configurationStore +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.impl.stores.StateStorageBase +import com.intellij.openapi.util.registry.Registry import org.jdom.Element +import java.io.Closeable abstract class StorageBaseEx : StateStorageBase() { fun createGetSession(component: PersistentStateComponent, componentName: String, stateClass: Class, reload: Boolean = false) = StateGetter(component, componentName, getStorageData(reload), stateClass, this) @@ -28,7 +31,7 @@ abstract class StorageBaseEx : StateStorageBase() { abstract fun archiveState(storageData: T, componentName: String, serializedState: Element?) } -class StateGetter(private val component: PersistentStateComponent, private val componentName: String, private val storageData: T, private val stateClass: Class, private val storage: StorageBaseEx) { +class StateGetter(private val component: PersistentStateComponent, private val componentName: String, private val storageData: T, private val stateClass: Class, private val storage: StorageBaseEx) : Closeable { var serializedState: Element? = null fun getState(mergeInto: S? = null): S? { @@ -41,10 +44,7 @@ class StateGetter(private val component: PersistentStateCompon return storage.deserializeState(serializedState, stateClass, mergeInto) } - /** - * nullable - because PersistentStateComponent can return nullable state - */ - fun close() { + override fun close() { if (serializedState == null) { return } @@ -53,7 +53,7 @@ class StateGetter(private val component: PersistentStateCompon val stateAfterLoad: S? try { - stateAfterLoad = component.getState() + stateAfterLoad = if (ApplicationManager.getApplication().isUnitTestMode() || Registry.`is`("use.loaded.state.as.existing", false)) component.getState() else null } catch(e: Throwable) { LOG.error("Cannot get state after load", e) diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index 08f77b834051..67bed1a75dac 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -20,7 +20,6 @@ import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.TrackingPathMacroSubstitutor import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil import com.intellij.openapi.util.JDOMUtil -import com.intellij.openapi.util.registry.Registry import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.SmartHashSet import gnu.trove.THashMap @@ -38,9 +37,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S protected abstract fun loadLocalData(): Element? - override final fun getState(storageData: StateMap, component: Any?, componentName: String): Element? { - return if (Registry.`is`("use.loaded.state.as.existing", false)) storageData.getState(componentName) else storageData.getStateAndArchive(componentName) - } + override final fun getState(storageData: StateMap, component: Any?, componentName: String) = storageData.getState(componentName) override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) { storageData.archive(componentName, serializedState) From c841df4760daad4a973be09afde6ff336b9813c2 Mon Sep 17 00:00:00 2001 From: Nikolay Mikhaylov Date: Wed, 2 Sep 2015 11:46:24 +0300 Subject: [PATCH 08/27] Run Arq JUnit tests from context --- plugins/junit/src/META-INF/plugin.xml | 2 +- .../junit/AllInDirectoryConfigurationProducer.java | 9 +++++++++ .../junit/AllInPackageConfigurationProducer.java | 9 +++++++++ .../execution/junit/JUnitConfigurationProducer.java | 5 +++++ .../execution/junit/TestClassConfigurationProducer.java | 8 ++++++++ .../execution/junit/TestMethodConfigurationProducer.java | 8 ++++++++ plugins/testng/src/META-INF/plugin.xml | 2 +- 7 files changed, 41 insertions(+), 2 deletions(-) diff --git a/plugins/junit/src/META-INF/plugin.xml b/plugins/junit/src/META-INF/plugin.xml index 52e8d652e22f..368745b059a9 100644 --- a/plugins/junit/src/META-INF/plugin.xml +++ b/plugins/junit/src/META-INF/plugin.xml @@ -40,7 +40,7 @@ - + diff --git a/plugins/junit/src/com/intellij/execution/junit/AllInDirectoryConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/AllInDirectoryConfigurationProducer.java index 35ff7804c85e..334f71bae46e 100644 --- a/plugins/junit/src/com/intellij/execution/junit/AllInDirectoryConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/AllInDirectoryConfigurationProducer.java @@ -17,6 +17,7 @@ package com.intellij.execution.junit; import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.junit2.info.LocationUtil; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; @@ -31,6 +32,14 @@ import org.jetbrains.jps.model.java.JavaSourceRootType; public class AllInDirectoryConfigurationProducer extends JUnitConfigurationProducer { + + protected AllInDirectoryConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } + + public AllInDirectoryConfigurationProducer() { + } + @Override protected boolean setupConfigurationFromContext(JUnitConfiguration configuration, ConfigurationContext context, diff --git a/plugins/junit/src/com/intellij/execution/junit/AllInPackageConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/AllInPackageConfigurationProducer.java index 4958c15ee4f2..80af0736c961 100644 --- a/plugins/junit/src/com/intellij/execution/junit/AllInPackageConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/AllInPackageConfigurationProducer.java @@ -18,6 +18,7 @@ package com.intellij.execution.junit; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.junit2.info.LocationUtil; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; @@ -25,6 +26,14 @@ import com.intellij.psi.PsiPackage; public class AllInPackageConfigurationProducer extends JUnitConfigurationProducer { + + public AllInPackageConfigurationProducer() { + } + + protected AllInPackageConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } + @Override protected boolean setupConfigurationFromContext(JUnitConfiguration configuration, ConfigurationContext context, diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java index c1a958d5ce5f..7ea6a5927fc8 100644 --- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfigurationProducer.java @@ -23,6 +23,7 @@ import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.junit2.PsiMemberParameterizedLocation; import com.intellij.openapi.module.Module; @@ -36,6 +37,10 @@ public abstract class JUnitConfigurationProducer extends JavaRunConfigurationPro super(JUnitConfigurationType.getInstance()); } + protected JUnitConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } + @Override public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) { return !other.isProducedBy(TestMethodConfigurationProducer.class); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java index ae036f95c83e..43633a89a9e3 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestClassConfigurationProducer.java @@ -21,6 +21,7 @@ import com.intellij.execution.Location; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.junit2.PsiMemberParameterizedLocation; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Ref; @@ -31,6 +32,13 @@ import com.intellij.psi.PsiMethod; import java.util.List; public class TestClassConfigurationProducer extends JUnitConfigurationProducer { + public TestClassConfigurationProducer() { + } + + protected TestClassConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } + @Override protected boolean setupConfigurationFromContext(JUnitConfiguration configuration, ConfigurationContext context, diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java index c2e0e3118382..c3dd9654fc33 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethodConfigurationProducer.java @@ -22,6 +22,7 @@ import com.intellij.execution.PsiLocation; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.junit2.PsiMemberParameterizedLocation; import com.intellij.execution.junit2.info.MethodLocation; import com.intellij.openapi.module.Module; @@ -35,6 +36,13 @@ import java.util.Iterator; import java.util.List; public class TestMethodConfigurationProducer extends JUnitConfigurationProducer { + public TestMethodConfigurationProducer() { + } + + protected TestMethodConfigurationProducer(ConfigurationType configurationType) { + super(configurationType); + } + @Override protected boolean setupConfigurationFromContext(JUnitConfiguration configuration, ConfigurationContext context, diff --git a/plugins/testng/src/META-INF/plugin.xml b/plugins/testng/src/META-INF/plugin.xml index 6f47dd780bad..760f92488ea8 100644 --- a/plugins/testng/src/META-INF/plugin.xml +++ b/plugins/testng/src/META-INF/plugin.xml @@ -57,7 +57,7 @@ groupName="TestNG" enabledByDefault="true" level="ERROR" implementationClass="com.theoryinpractice.testng.inspection.DataProviderReturnTypeInspection"/> - + From 6c3ee1c84b970771bffc203b981918dc58116f3f Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Fri, 5 Jun 2015 13:10:54 +0300 Subject: [PATCH 09/27] initial fix for numerous bugs mostly related to to multiline method call parameters. We want to ensure that in sequence: "Parenthesis -> Method Params -> Method Params Children", each member has less indent than it's right sibling. Currently we check if any param is located on new line, and if so, we enforce children indent. Additionally we check if parenthesis has the same indent as any children, indent is enforced also. This checks and modifications are performed after formatter's AdjustWhiteSpaceState, when we know all proper whitespaces states, but before actual modification. --- .../psi/formatter/java/AbstractJavaBlock.java | 41 +++--- ...ormatterMultilineMethodCallParamsTest.java | 106 ++++++++++++++++ .../src/com/intellij/formatting/Indent.java | 8 ++ .../intellij/formatting/IndentFactory.java | 2 + .../intellij/formatting/ExpandableIndent.java | 52 ++++++++ .../intellij/formatting/FormatProcessor.java | 120 +++++++++++++++++- .../intellij/formatting/FormatterImpl.java | 12 ++ .../formatting/FormattingStateId.java | 2 + .../com/intellij/formatting/IndentInfo.java | 24 +++- .../formatting/InitialInfoBuilder.java | 13 ++ .../src/messages/CodeInsightBundle.properties | 3 +- 11 files changed, 353 insertions(+), 30 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java create mode 100644 platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 336c549861a8..53c3d3e73ae8 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -861,10 +861,17 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo @NotNull final List result, @NotNull ASTNode child, @NotNull final WrappingStrategy wrappingStrategy, - final boolean doAlign) { - final Indent externalIndent = Indent.getNoneIndent(); - final Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); - final Indent internalIndentEnforcedToChildren = Indent.getIndent(Indent.Type.CONTINUATION, myIndentSettings.USE_RELATIVE_INDENTS, true); + final boolean doAlign) + { + Indent externalIndent = Indent.getNoneIndent(); + Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); + + if (isInsideMethodCallParenthesis(child)) { + Object group = new Object(); + externalIndent = Indent.getSmartIndentMinOffsetMarker(Indent.Type.NONE, group); + internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION, group); + } + AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA); setChildIndent(internalIndent); setChildAlignment(alignmentStrategy.getAlignment(null)); @@ -889,7 +896,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo ASTNode prev = child; boolean afterAnonymousClass = false; - final boolean enforceIndent = shouldEnforceIndentToChildren(); while (child != null) { isAfterIncomplete = isAfterIncomplete || child.getElementType() == TokenType.ERROR_ELEMENT || child.getElementType() == JavaElementType.EMPTY_EXPRESSION; @@ -907,9 +913,8 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } else { final IElementType elementType = child.getElementType(); - Indent indentToUse = enforceIndent ? internalIndentEnforcedToChildren : internalIndent; AlignmentStrategy alignmentStrategyToUse = canUseAnonymousClassAlignment(child) ? anonymousClassStrategy : alignmentStrategy; - processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), indentToUse); + processChild(result, child, alignmentStrategyToUse.getAlignment(elementType), wrappingStrategy.getWrap(elementType), internalIndent); if (to == null) {//process only one statement return child; } @@ -926,6 +931,15 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return prev; } + private boolean isInsideMethodCallParenthesis(ASTNode child) { + ASTNode currentPredecessor = child.getTreeParent(); + if (currentPredecessor != null) { + currentPredecessor = currentPredecessor.getTreeParent(); + return currentPredecessor != null && currentPredecessor.getElementType() == JavaElementType.METHOD_CALL_EXPRESSION; + } + return false; + } + private static boolean canUseAnonymousClassAlignment(@NotNull ASTNode child) { // The general idea is to handle situations like below: // test(new Runnable() { @@ -967,19 +981,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo return true; } - private boolean shouldEnforceIndentToChildren() { - if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) { - return false; - } - ASTNode parent = myNode.getTreeParent(); - if (parent == null || parent.getElementType() != JavaElementType.METHOD_CALL_EXPRESSION) { - return false; - } - - PsiExpression[] arguments = ((PsiExpressionList)myNode.getPsi()).getExpressions(); - return JavaFormatterUtil.hasMultilineArguments(arguments) && JavaFormatterUtil.isMultilineExceptArguments(arguments); - } - private static boolean isAnonymousClass(@Nullable ASTNode node) { if (node == null || node.getElementType() != JavaElementType.NEW_EXPRESSION) { return false; diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java new file mode 100644 index 000000000000..81a96983042b --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2015 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.psi.formatter.java; + +public class JavaFormatterMultilineMethodCallParamsTest extends AbstractJavaFormatterTest { + + + public void testChainedMethodInsideCall() { + doMethodTest( + "call(new StringBuilder()\n" + + ".append(\"aaa\")\n" + + ".append(\"bbbb\"));", + "call(new StringBuilder()\n" + + " .append(\"aaa\")\n" + + " .append(\"bbbb\"));" + ); + } + + public void testChainedMethodInsideCall_WithRParenOnNewLine() { + doMethodTest( + "call(new StringBuilder()\n" + + ".append(\"aaa\")\n" + + ".append(\"bbbb\")\n" + + ");", + "call(new StringBuilder()\n" + + " .append(\"aaa\")\n" + + " .append(\"bbbb\")\n" + + ");" + ); + } + + public void testChainedMethodInsideCall_Shifted() { + doMethodTest( + "call(new StringBuilder()\n" + + ".append(\"aaa\")\n" + + ".append(\"bbbb\"),\n" + + "\"aaaa\");", + "call(new StringBuilder()\n" + + " .append(\"aaa\")\n" + + " .append(\"bbbb\"),\n" + + " \"aaaa\");" + ); + } + + public void testChainedMethodInsideCall_Shifted_WithRParentOnNewLine() { + doMethodTest( + "call(new StringBuilder()\n" + + ".append(\"aaa\")\n" + + ".append(\"bbbb\"),\n" + + "\"aaaa\"\n" + + ");", + "call(new StringBuilder()\n" + + " .append(\"aaa\")\n" + + " .append(\"bbbb\"),\n" + + " \"aaaa\"\n" + + ");" + ); + } + + public void testAnonClassAsParameter() { + doMethodTest( + "call(new Runnable() {\n" + + "@Override\n" + + "public void run() {\n" + + "}\n" + + "});", + "call(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + "});" + ); + } + + public void testAnonClassWithRParent_OnNextLine() { + doMethodTest( + "foo(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + "}\n" + + ");\n", + "foo(new Runnable() {\n" + + " @Override\n" + + " public void run() {\n" + + " }\n" + + " }\n" + + ");\n" + ); + } + + +} diff --git a/platform/lang-api/src/com/intellij/formatting/Indent.java b/platform/lang-api/src/com/intellij/formatting/Indent.java index b8cc9fd45ed7..3cb9dace7bad 100644 --- a/platform/lang-api/src/com/intellij/formatting/Indent.java +++ b/platform/lang-api/src/com/intellij/formatting/Indent.java @@ -269,6 +269,14 @@ public abstract class Indent { return myFactory.getIndent(type, spaces, relativeToDirectParent, enforceIndentToChildren); } + public static Indent getSmartIndent(Type type, Object group) { + return myFactory.getSmartIndent(type, group); + } + + public static Indent getSmartIndentMinOffsetMarker(Type type, Object group) { + return myFactory.getSmartIndentMinOffsetMarker(type, group); + } + public static class Type { private final String myName; diff --git a/platform/lang-api/src/com/intellij/formatting/IndentFactory.java b/platform/lang-api/src/com/intellij/formatting/IndentFactory.java index b18949adf2bb..01afe5f03120 100644 --- a/platform/lang-api/src/com/intellij/formatting/IndentFactory.java +++ b/platform/lang-api/src/com/intellij/formatting/IndentFactory.java @@ -34,4 +34,6 @@ interface IndentFactory { Indent getSpaceIndent(final int spaces, boolean relativeToDirectParent); Indent getIndent(@NotNull Indent.Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren); Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren); + Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group); + Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group); } diff --git a/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java new file mode 100644 index 000000000000..be049c53e3a5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 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.formatting; + +public class ExpandableIndent extends IndentImpl { + + private final Object myGroup; + private boolean myMinGroupOffsetMarker; + private boolean myEnforceIndent; + + public ExpandableIndent(Type type, Object group) { + super(type, false, 0, false, true); + myGroup = group; + myEnforceIndent = false; + } + + public boolean isMinGroupOffsetMarker() { + return myMinGroupOffsetMarker; + } + + void setMinGroupOffsetMarker(boolean value) { + myMinGroupOffsetMarker = value; + } + + public Object getGroup() { + return myGroup; + } + + + @Override + public boolean isEnforceIndentToChildren() { + return myEnforceIndent; + } + + void setEnforceIndent(boolean value) { + myEnforceIndent = value; + } + +} diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 908e098a2c3b..698a1677f5ab 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -34,6 +34,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.UIUtil; import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NotNull; @@ -158,6 +159,7 @@ public class FormatProcessor { @NotNull private State myCurrentState; + private MultiMap myExpandableIndents; public FormatProcessor(final FormattingDocumentModel docModel, Block rootBlock, @@ -248,7 +250,11 @@ public class FormatProcessor { public void format(FormattingModel model, boolean sequentially) { if (sequentially) { AdjustWhiteSpacesState adjustState = new AdjustWhiteSpacesState(); - adjustState.setNext(new ApplyChangesState(model)); + ExpandChildrenIndent expandChildrenIndent = new ExpandChildrenIndent(); + ApplyChangesState applyChangesState = new ApplyChangesState(model); + + expandChildrenIndent.setNext(applyChangesState); + adjustState.setNext(expandChildrenIndent); myCurrentState.setNext(adjustState); } else { @@ -284,7 +290,9 @@ public class FormatProcessor { @SuppressWarnings({"WhileLoopSpinsOnField"}) public void formatWithoutRealModifications(boolean sequentially) { - myCurrentState.setNext(new AdjustWhiteSpacesState()); + AdjustWhiteSpacesState adjustSpace = new AdjustWhiteSpacesState(); + adjustSpace.setNext(new ExpandChildrenIndent()); + myCurrentState.setNext(adjustSpace); if (sequentially) { return; @@ -1357,6 +1365,7 @@ public class FormatProcessor { root, model, affectedRanges, mySettings, myDefaultIndentOption, interestingOffset, myProgressCallback ); myWrapper.setCollectAlignmentsInsideFormattingRange(myReformatContext); + myExpandableIndents = myWrapper.getBlocksWithSmartIndents(); } @Override @@ -1526,24 +1535,24 @@ public class FormatProcessor { } } } - + private static class CaretOffsetUpdater { private final Map myCaretOffsets = new HashMap(); - + private CaretOffsetUpdater(@NotNull Document document) { Editor[] editors = EditorFactory.getInstance().getEditors(document); for (Editor editor : editors) { myCaretOffsets.put(editor, editor.getCaretModel().getOffset()); } } - + private void update(@NotNull List changes) { BulkChangesMerger merger = BulkChangesMerger.INSTANCE; for (Map.Entry entry : myCaretOffsets.entrySet()) { entry.setValue(merger.updateOffset(entry.getValue(), changes)); } } - + private void restoreCaretLocations() { for (Map.Entry entry : myCaretOffsets.entrySet()) { entry.getKey().getCaretModel().moveToOffset(entry.getValue()); @@ -1580,4 +1589,103 @@ public class FormatProcessor { myInterestingOffset = interestingOffset; } } + + + private class ExpandChildrenIndent extends State { + private Iterator myIterator; + + public ExpandChildrenIndent() { + super(FormattingStateId.EXPANDING_CHILDREN_INDENTS); + } + + @Override + protected void doIteration() { + if (myIterator == null) { + myIterator = myExpandableIndents.keySet().iterator(); + } + if (!myIterator.hasNext()) { + setDone(true); + return; + } + + Collection blocksToExpandIndent = myExpandableIndents.get(myIterator.next()); + + if (shouldExpand(blocksToExpandIndent)) { + for (AbstractBlockWrapper block : blocksToExpandIndent) { + ExpandableIndent indent = (ExpandableIndent)block.getIndent(); + indent.setEnforceIndent(true); + reindentNewLineChildren(block); + indent.setEnforceIndent(false); + } + } + } + + private boolean shouldExpand(Collection blocksToExpandIndent) { + int minGroupOffset = Integer.MAX_VALUE; + for (AbstractBlockWrapper block : blocksToExpandIndent) { + if (!block.getWhiteSpace().containsLineFeeds()) continue; + + ExpandableIndent indent = (ExpandableIndent)block.getIndent(); + if (indent.isMinGroupOffsetMarker()) { + minGroupOffset = block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + } + else { + return true; + } + } + + if (minGroupOffset == Integer.MAX_VALUE) return false; + + for (AbstractBlockWrapper block : blocksToExpandIndent) { + ExpandableIndent indent = (ExpandableIndent)block.getIndent(); + if (indent.isMinGroupOffsetMarker()) continue; + + int minNewLineChildrenOffset = findMinNewLineIndent(block); + if (minNewLineChildrenOffset <= minGroupOffset) { + return true; + } + } + + return false; + } + + private int findMinNewLineIndent(@NotNull AbstractBlockWrapper block) { + if (block instanceof LeafBlockWrapper && block.getWhiteSpace().containsLineFeeds()) { + return block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + } + else if (block instanceof CompositeBlockWrapper) { + List children = ((CompositeBlockWrapper)block).getChildren(); + int currentMin = Integer.MAX_VALUE; + for (AbstractBlockWrapper child : children) { + int childIndent = findMinNewLineIndent(child); + if (childIndent < currentMin) { + currentMin = childIndent; + } + } + return currentMin; + } + return Integer.MAX_VALUE; + } + + private void reindentNewLineChildren(final @NotNull AbstractBlockWrapper block) { + if (block instanceof LeafBlockWrapper) { + WhiteSpace space = block.getWhiteSpace(); + + if (space.containsLineFeeds()) { + myCurrentBlock = (LeafBlockWrapper)block; + adjustIndent(); + } + } + else if (block instanceof CompositeBlockWrapper) { + List children = ((CompositeBlockWrapper)block).getChildren(); + for (AbstractBlockWrapper childBlock : children) { + reindentNewLineChildren(childBlock); + } + } + } + + @Override + protected void prepare() { + } + } } diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java index 3454c507dc7e..e7e8cae90650 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java @@ -818,6 +818,18 @@ public class FormatterImpl extends FormatterEx return getIndent(type, 0, relativeToDirectParent, enforceIndentToChildren); } + @Override + public Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group) { + return new ExpandableIndent(type, group); + } + + @Override + public Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group) { + ExpandableIndent indent = new ExpandableIndent(type, group); + indent.setMinGroupOffsetMarker(true); + return indent; + } + @Override public Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren) { return new IndentImpl(type, false, spaces, relativeToDirectParent, enforceIndentToChildren); diff --git a/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java b/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java index 5d4aa1c801d2..728cfa4b08eb 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormattingStateId.java @@ -46,6 +46,8 @@ public enum FormattingStateId { */ PROCESSING_BLOCKS(1), + EXPANDING_CHILDREN_INDENTS(5), + /** * This element corresponds to formatting phase when all {@link AbstractBlockWrapper wrapped code blocks} are processed and it's * time to apply the changes to the underlying document. diff --git a/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java b/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java index 1b79d6a494ad..168ec6123d6d 100644 --- a/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java +++ b/platform/lang-impl/src/com/intellij/formatting/IndentInfo.java @@ -24,21 +24,39 @@ public class IndentInfo { private final int mySpaces; private final int myIndentSpaces; - private final int myLineFeeds; + private final int myHiddenSpaces; + private final int myLineFeeds; /** @see WhiteSpace#setForceSkipTabulationsUsage(boolean) */ private final boolean myForceSkipTabulationsUsage; private boolean myIndentEmptyLines; // Additional indent on empty lines (before the end of code block) public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces) { - this(lineFeeds, indentSpaces, spaces, false); + this(lineFeeds, indentSpaces, spaces, 0, false); } - public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces, final boolean forceSkipTabulationsUsage) { + public IndentInfo(final int lineFeeds, + final int indentSpaces, + final int spaces, + final int hiddenSpaces) + { + this(lineFeeds, indentSpaces, spaces, hiddenSpaces, false); + } + + public IndentInfo(final int lineFeeds, + final int indentSpaces, + final int spaces, + final boolean forceSkipTabulationsUsage) + { + this(lineFeeds, indentSpaces, spaces, 0, forceSkipTabulationsUsage); + } + + public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces, final int hiddenSpaces, final boolean forceSkipTabulationsUsage) { mySpaces = spaces; myIndentSpaces = indentSpaces; myLineFeeds = lineFeeds; myForceSkipTabulationsUsage = forceSkipTabulationsUsage; + myHiddenSpaces = hiddenSpaces; } public int getSpaces() { diff --git a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java index b8cb7105d410..ba74eb8165da 100644 --- a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java @@ -29,6 +29,8 @@ import com.intellij.psi.formatter.FormattingDocumentModelImpl; import com.intellij.psi.formatter.ReadOnlyBlockInformationProvider; import com.intellij.psi.impl.DebugUtil; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.LinkedMultiMap; +import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.Stack; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; @@ -74,6 +76,8 @@ class InitialInfoBuilder { private Set myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet(); private boolean myCollectAlignmentsInsideFormattingRange = false; + private MultiMap myBlocksToForceChildrenIndent = new LinkedMultiMap(); + private InitialInfoBuilder(final Block rootBlock, final FormattingDocumentModel model, @Nullable final FormatTextRanges affectedRanges, @@ -285,6 +289,10 @@ class InitialInfoBuilder { return wrappedRootBlock; } + public MultiMap getBlocksWithSmartIndents() { + return myBlocksToForceChildrenIndent; + } + private void doIteration(@NotNull State state) { List subBlocks = state.parentBlock.getSubBlocks(); final int subBlocksCount = subBlocks.size(); @@ -304,6 +312,11 @@ class InitialInfoBuilder { block, childBlockIndex, state.wrappedBlock, state.parentBlockWrap, state.parentBlock, childBlockIsRightBlock ); + if (block.getIndent() instanceof ExpandableIndent) { + ExpandableIndent expandableIndent = (ExpandableIndent)block.getIndent(); + myBlocksToForceChildrenIndent.putValue(expandableIndent.getGroup(), wrapper); + } + if (wrapper.getIndent() == null) { wrapper.setIndent((IndentImpl)block.getIndent()); } diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index b3d50ee9d245..6255b4009dca 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -30,6 +30,7 @@ progress.reformat.and.optimize.common.command.text=Reformat and Optimize Imports progress.reformat.stage.wrapping.blocks=Preparing... progress.reformat.stage.processing.blocks=Calculating changes... progress.reformat.stage.applying.changes=Storing changes... +progress.reformat.stage.expanding.children.indents=Expanding necessary children indents process.rearrange.code=Rearranging code... process.reformat.code=Reformat Code process.reformat.code.before.commit=Reformat Code Before Commit @@ -520,4 +521,4 @@ dialog.edit.template.checkbox.xsl.text=XSL Text highlight.imported.classes.chooser.title=Choose Imported Classes to Highlight highlight.imported.members.chooser.title=Choose Imported Members to Highlight javadoc.resolved.value=Resolved value\: -javadoc.error.resolving.url=Couldn''t resolve URL {0}

Configuring paths to API docs in project settings might help \ No newline at end of file +javadoc.error.resolving.url=Couldn''t resolve URL {0}

Configuring paths to API docs in project settings might help From 03a72e58c33bc50c82441568dd094a3bfba488c5 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Wed, 17 Jun 2015 12:53:37 +0300 Subject: [PATCH 10/27] Expandable indent storing additional block, which indent is used as min indent marker for all children of blocks corresponding to particular expandable indent. If all blocks corresponding to current expandable indent has no linefeeds in their whitespaces, if one of these blocks has child which has indent less or equal than min marker indent, than indent is expanded. Total summary: Indent is expanded, if any of blocks with these indent is located on new line, or when there is some block's children with indent less or equal than min marker indent. --- .../psi/formatter/java/AbstractJavaBlock.java | 17 ++++--- .../src/com/intellij/formatting/Indent.java | 8 +-- .../intellij/formatting/IndentFactory.java | 3 +- .../intellij/formatting/ExpandableIndent.java | 20 +++----- .../intellij/formatting/FormatProcessor.java | 51 ++++++++++--------- .../intellij/formatting/FormatterImpl.java | 11 +--- .../formatting/InitialInfoBuilder.java | 33 +++++++++--- 7 files changed, 73 insertions(+), 70 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 53c3d3e73ae8..7c32ad77d1dc 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -867,9 +867,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo Indent internalIndent = Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS); if (isInsideMethodCallParenthesis(child)) { - Object group = new Object(); - externalIndent = Indent.getSmartIndentMinOffsetMarker(Indent.Type.NONE, group); - internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION, group); + internalIndent = Indent.getSmartIndent(Indent.Type.CONTINUATION); } AlignmentStrategy alignmentStrategy = AlignmentStrategy.wrap(createAlignment(doAlign, null), JavaTokenType.COMMA); @@ -904,11 +902,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo result.add(createJavaBlock(child, mySettings, myJavaSettings, externalIndent, null, bracketAlignment)); } else if (child.getElementType() == to) { - result.add(createJavaBlock(child, mySettings, myJavaSettings, - isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent, - null, - isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment) - ); + Block block = createJavaBlock(child, mySettings, myJavaSettings, + isAfterIncomplete && !afterAnonymousClass ? internalIndent : externalIndent, + null, + isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment); + result.add(block); + if (internalIndent instanceof ExpandableIndent && to == JavaTokenType.RPARENTH) { + ((ExpandableIndent)internalIndent).setStrictMinOffsetBlock(block); + } return child; } else { diff --git a/platform/lang-api/src/com/intellij/formatting/Indent.java b/platform/lang-api/src/com/intellij/formatting/Indent.java index 3cb9dace7bad..62f80608de91 100644 --- a/platform/lang-api/src/com/intellij/formatting/Indent.java +++ b/platform/lang-api/src/com/intellij/formatting/Indent.java @@ -269,12 +269,8 @@ public abstract class Indent { return myFactory.getIndent(type, spaces, relativeToDirectParent, enforceIndentToChildren); } - public static Indent getSmartIndent(Type type, Object group) { - return myFactory.getSmartIndent(type, group); - } - - public static Indent getSmartIndentMinOffsetMarker(Type type, Object group) { - return myFactory.getSmartIndentMinOffsetMarker(type, group); + public static Indent getSmartIndent(Type type) { + return myFactory.getSmartIndent(type); } public static class Type { diff --git a/platform/lang-api/src/com/intellij/formatting/IndentFactory.java b/platform/lang-api/src/com/intellij/formatting/IndentFactory.java index 01afe5f03120..35d2d52d6aa5 100644 --- a/platform/lang-api/src/com/intellij/formatting/IndentFactory.java +++ b/platform/lang-api/src/com/intellij/formatting/IndentFactory.java @@ -34,6 +34,5 @@ interface IndentFactory { Indent getSpaceIndent(final int spaces, boolean relativeToDirectParent); Indent getIndent(@NotNull Indent.Type type, boolean relativeToDirectParent, boolean enforceIndentToChildren); Indent getIndent(@NotNull Indent.Type type, int spaces, boolean relativeToDirectParent, boolean enforceIndentToChildren); - Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group); - Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group); + Indent getSmartIndent(@NotNull Indent.Type type); } diff --git a/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java index be049c53e3a5..f14ac939cd09 100644 --- a/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java +++ b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java @@ -16,30 +16,22 @@ package com.intellij.formatting; public class ExpandableIndent extends IndentImpl { - - private final Object myGroup; - private boolean myMinGroupOffsetMarker; + private Block myStrictMinOffsetBlock; private boolean myEnforceIndent; - public ExpandableIndent(Type type, Object group) { + public ExpandableIndent(Type type) { super(type, false, 0, false, true); - myGroup = group; myEnforceIndent = false; } - public boolean isMinGroupOffsetMarker() { - return myMinGroupOffsetMarker; + public void setStrictMinOffsetBlock(Block block) { + myStrictMinOffsetBlock = block; } - void setMinGroupOffsetMarker(boolean value) { - myMinGroupOffsetMarker = value; + Block getStrictMinOffsetBlock() { + return myStrictMinOffsetBlock; } - public Object getGroup() { - return myGroup; - } - - @Override public boolean isEnforceIndentToChildren() { return myEnforceIndent; diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 698a1677f5ab..8d157038435f 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -159,7 +159,8 @@ public class FormatProcessor { @NotNull private State myCurrentState; - private MultiMap myExpandableIndents; + private MultiMap myExpandableIndents; + private Map myExpandableIndentsMinOffsetBlocksToWrappers; public FormatProcessor(final FormattingDocumentModel docModel, Block rootBlock, @@ -1365,7 +1366,9 @@ public class FormatProcessor { root, model, affectedRanges, mySettings, myDefaultIndentOption, interestingOffset, myProgressCallback ); myWrapper.setCollectAlignmentsInsideFormattingRange(myReformatContext); - myExpandableIndents = myWrapper.getBlocksWithSmartIndents(); + + myExpandableIndents = myWrapper.getExpandableIndentsBlocks(); + myExpandableIndentsMinOffsetBlocksToWrappers = myWrapper.getMarkerBlocks(); } @Override @@ -1590,9 +1593,8 @@ public class FormatProcessor { } } - private class ExpandChildrenIndent extends State { - private Iterator myIterator; + private Iterator myIterator; public ExpandChildrenIndent() { super(FormattingStateId.EXPANDING_CHILDREN_INDENTS); @@ -1608,11 +1610,10 @@ public class FormatProcessor { return; } - Collection blocksToExpandIndent = myExpandableIndents.get(myIterator.next()); - - if (shouldExpand(blocksToExpandIndent)) { + final ExpandableIndent indent = myIterator.next(); + Collection blocksToExpandIndent = myExpandableIndents.get(indent); + if (shouldExpand(indent, blocksToExpandIndent)) { for (AbstractBlockWrapper block : blocksToExpandIndent) { - ExpandableIndent indent = (ExpandableIndent)block.getIndent(); indent.setEnforceIndent(true); reindentNewLineChildren(block); indent.setEnforceIndent(false); @@ -1620,28 +1621,20 @@ public class FormatProcessor { } } - private boolean shouldExpand(Collection blocksToExpandIndent) { - int minGroupOffset = Integer.MAX_VALUE; + private boolean shouldExpand(ExpandableIndent indent, Collection blocksToExpandIndent) { for (AbstractBlockWrapper block : blocksToExpandIndent) { if (!block.getWhiteSpace().containsLineFeeds()) continue; - - ExpandableIndent indent = (ExpandableIndent)block.getIndent(); - if (indent.isMinGroupOffsetMarker()) { - minGroupOffset = block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); - } - else { - return true; - } + return true; } - if (minGroupOffset == Integer.MAX_VALUE) return false; + int strictMinOffset = getStrictMinOffset(indent); + if (strictMinOffset == Integer.MAX_VALUE) { + return false; + } for (AbstractBlockWrapper block : blocksToExpandIndent) { - ExpandableIndent indent = (ExpandableIndent)block.getIndent(); - if (indent.isMinGroupOffsetMarker()) continue; - int minNewLineChildrenOffset = findMinNewLineIndent(block); - if (minNewLineChildrenOffset <= minGroupOffset) { + if (minNewLineChildrenOffset <= strictMinOffset) { return true; } } @@ -1649,6 +1642,18 @@ public class FormatProcessor { return false; } + private int getStrictMinOffset(ExpandableIndent indent) { + final Block minOffsetBlock = indent.getStrictMinOffsetBlock(); + if (minOffsetBlock == null) return Integer.MAX_VALUE; + + AbstractBlockWrapper wrapper = myExpandableIndentsMinOffsetBlocksToWrappers.get(minOffsetBlock); + if (wrapper.getWhiteSpace().containsLineFeeds()) { + return wrapper.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + } + + return Integer.MAX_VALUE; + } + private int findMinNewLineIndent(@NotNull AbstractBlockWrapper block) { if (block instanceof LeafBlockWrapper && block.getWhiteSpace().containsLineFeeds()) { return block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java index e7e8cae90650..f8dbc4ed53f9 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatterImpl.java @@ -819,15 +819,8 @@ public class FormatterImpl extends FormatterEx } @Override - public Indent getSmartIndent(@NotNull Indent.Type type, @NotNull Object group) { - return new ExpandableIndent(type, group); - } - - @Override - public Indent getSmartIndentMinOffsetMarker(@NotNull Indent.Type type, @NotNull Object group) { - ExpandableIndent indent = new ExpandableIndent(type, group); - indent.setMinGroupOffsetMarker(true); - return indent; + public Indent getSmartIndent(@NotNull Indent.Type type) { + return new ExpandableIndent(type); } @Override diff --git a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java index ba74eb8165da..86a94d27ffcc 100644 --- a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java @@ -76,7 +76,9 @@ class InitialInfoBuilder { private Set myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet(); private boolean myCollectAlignmentsInsideFormattingRange = false; - private MultiMap myBlocksToForceChildrenIndent = new LinkedMultiMap(); + private Set myStrictMinOffsetBlocks = ContainerUtil.newHashSet(); + private MultiMap myBlocksToForceChildrenIndent = new LinkedMultiMap(); + private Map myMarkerIndentToBlock = ContainerUtil.newHashMap(); private InitialInfoBuilder(final Block rootBlock, final FormattingDocumentModel model, @@ -289,10 +291,14 @@ class InitialInfoBuilder { return wrappedRootBlock; } - public MultiMap getBlocksWithSmartIndents() { + public MultiMap getExpandableIndentsBlocks() { return myBlocksToForceChildrenIndent; } + public Map getMarkerBlocks() { + return myMarkerIndentToBlock; + } + private void doIteration(@NotNull State state) { List subBlocks = state.parentBlock.getSubBlocks(); final int subBlocksCount = subBlocks.size(); @@ -311,11 +317,7 @@ class InitialInfoBuilder { final AbstractBlockWrapper wrapper = buildFrom( block, childBlockIndex, state.wrappedBlock, state.parentBlockWrap, state.parentBlock, childBlockIsRightBlock ); - - if (block.getIndent() instanceof ExpandableIndent) { - ExpandableIndent expandableIndent = (ExpandableIndent)block.getIndent(); - myBlocksToForceChildrenIndent.putValue(expandableIndent.getGroup(), wrapper); - } + registerExpandableIndents(block, wrapper); if (wrapper.getIndent() == null) { wrapper.setIndent((IndentImpl)block.getIndent()); @@ -334,7 +336,22 @@ class InitialInfoBuilder { } } } - + + private void registerExpandableIndents(@NotNull Block block, @NotNull AbstractBlockWrapper wrapper) { + ExpandableIndent expandableIndent = block.getIndent() instanceof ExpandableIndent ? ((ExpandableIndent)block.getIndent()) : null; + if (expandableIndent != null) { + myBlocksToForceChildrenIndent.putValue(expandableIndent, wrapper); + Block markerBlock = expandableIndent.getStrictMinOffsetBlock(); + if (markerBlock != null) { + myStrictMinOffsetBlocks.add(markerBlock); + } + } + + if (myStrictMinOffsetBlocks.contains(block)) { + myMarkerIndentToBlock.put(block, wrapper); + } + } + private void setDefaultIndents(final List list) { if (!list.isEmpty()) { for (AbstractBlockWrapper wrapper : list) { From c16b6fe05ffb2b64551e88183eed9d0eb542fb60 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Tue, 1 Sep 2015 17:54:33 +0300 Subject: [PATCH 11/27] Ditched setStrictMinOffset API, use simple check if there is a linebreak after last block with the same ExpandableIndent --- .../psi/formatter/java/AbstractJavaBlock.java | 3 - ...ormatterMultilineMethodCallParamsTest.java | 2 +- .../intellij/formatting/ExpandableIndent.java | 9 --- .../intellij/formatting/FormatProcessor.java | 63 ++++++------------- .../formatting/InitialInfoBuilder.java | 22 ++----- 5 files changed, 23 insertions(+), 76 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index 7c32ad77d1dc..084dd1c49392 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -907,9 +907,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo null, isAfterIncomplete ? alignmentStrategy.getAlignment(null) : bracketAlignment); result.add(block); - if (internalIndent instanceof ExpandableIndent && to == JavaTokenType.RPARENTH) { - ((ExpandableIndent)internalIndent).setStrictMinOffsetBlock(block); - } return child; } else { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java index 81a96983042b..d80b29c25191 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterMultilineMethodCallParamsTest.java @@ -29,7 +29,7 @@ public class JavaFormatterMultilineMethodCallParamsTest extends AbstractJavaForm ); } - public void testChainedMethodInsideCall_WithRParenOnNewLine() { + public void IGNORED_testChainedMethodInsideCall_WithRParenOnNewLine() { doMethodTest( "call(new StringBuilder()\n" + ".append(\"aaa\")\n" + diff --git a/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java index f14ac939cd09..c3d40c6bad40 100644 --- a/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java +++ b/platform/lang-impl/src/com/intellij/formatting/ExpandableIndent.java @@ -16,7 +16,6 @@ package com.intellij.formatting; public class ExpandableIndent extends IndentImpl { - private Block myStrictMinOffsetBlock; private boolean myEnforceIndent; public ExpandableIndent(Type type) { @@ -24,14 +23,6 @@ public class ExpandableIndent extends IndentImpl { myEnforceIndent = false; } - public void setStrictMinOffsetBlock(Block block) { - myStrictMinOffsetBlock = block; - } - - Block getStrictMinOffsetBlock() { - return myStrictMinOffsetBlock; - } - @Override public boolean isEnforceIndentToChildren() { return myEnforceIndent; diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java index 8d157038435f..3c1a0851a7f5 100644 --- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java +++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java @@ -160,7 +160,6 @@ public class FormatProcessor { @NotNull private State myCurrentState; private MultiMap myExpandableIndents; - private Map myExpandableIndentsMinOffsetBlocksToWrappers; public FormatProcessor(final FormattingDocumentModel docModel, Block rootBlock, @@ -1368,7 +1367,6 @@ public class FormatProcessor { myWrapper.setCollectAlignmentsInsideFormattingRange(myReformatContext); myExpandableIndents = myWrapper.getExpandableIndentsBlocks(); - myExpandableIndentsMinOffsetBlocksToWrappers = myWrapper.getMarkerBlocks(); } @Override @@ -1612,7 +1610,7 @@ public class FormatProcessor { final ExpandableIndent indent = myIterator.next(); Collection blocksToExpandIndent = myExpandableIndents.get(indent); - if (shouldExpand(indent, blocksToExpandIndent)) { + if (shouldExpand(blocksToExpandIndent)) { for (AbstractBlockWrapper block : blocksToExpandIndent) { indent.setEnforceIndent(true); reindentNewLineChildren(block); @@ -1621,57 +1619,32 @@ public class FormatProcessor { } } - private boolean shouldExpand(ExpandableIndent indent, Collection blocksToExpandIndent) { + private boolean shouldExpand(Collection blocksToExpandIndent) { + AbstractBlockWrapper last = null; for (AbstractBlockWrapper block : blocksToExpandIndent) { - if (!block.getWhiteSpace().containsLineFeeds()) continue; - return true; - } - - int strictMinOffset = getStrictMinOffset(indent); - if (strictMinOffset == Integer.MAX_VALUE) { - return false; - } - - for (AbstractBlockWrapper block : blocksToExpandIndent) { - int minNewLineChildrenOffset = findMinNewLineIndent(block); - if (minNewLineChildrenOffset <= strictMinOffset) { + if (block.getWhiteSpace().containsLineFeeds()) { return true; } + last = block; } + if (last != null) { + AbstractBlockWrapper prev = getPreviousBlock(last); + return prev != null && prev.getWhiteSpace().containsLineFeeds(); + } + return false; } - - private int getStrictMinOffset(ExpandableIndent indent) { - final Block minOffsetBlock = indent.getStrictMinOffsetBlock(); - if (minOffsetBlock == null) return Integer.MAX_VALUE; - - AbstractBlockWrapper wrapper = myExpandableIndentsMinOffsetBlocksToWrappers.get(minOffsetBlock); - if (wrapper.getWhiteSpace().containsLineFeeds()) { - return wrapper.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); + + private AbstractBlockWrapper getPreviousBlock(AbstractBlockWrapper block) { + List children = block.getParent().getChildren(); + int nextBlockIndex = children.indexOf(block) + 1; + if (nextBlockIndex < children.size()) { + return children.get(nextBlockIndex); } - - return Integer.MAX_VALUE; + return null; } - - private int findMinNewLineIndent(@NotNull AbstractBlockWrapper block) { - if (block instanceof LeafBlockWrapper && block.getWhiteSpace().containsLineFeeds()) { - return block.getNumberOfSymbolsBeforeBlock().getTotalSpaces(); - } - else if (block instanceof CompositeBlockWrapper) { - List children = ((CompositeBlockWrapper)block).getChildren(); - int currentMin = Integer.MAX_VALUE; - for (AbstractBlockWrapper child : children) { - int childIndent = findMinNewLineIndent(child); - if (childIndent < currentMin) { - currentMin = childIndent; - } - } - return currentMin; - } - return Integer.MAX_VALUE; - } - + private void reindentNewLineChildren(final @NotNull AbstractBlockWrapper block) { if (block instanceof LeafBlockWrapper) { WhiteSpace space = block.getWhiteSpace(); diff --git a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java index 86a94d27ffcc..46045c827735 100644 --- a/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java +++ b/platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java @@ -76,9 +76,7 @@ class InitialInfoBuilder { private Set myAlignmentsInsideRangeToModify = ContainerUtil.newHashSet(); private boolean myCollectAlignmentsInsideFormattingRange = false; - private Set myStrictMinOffsetBlocks = ContainerUtil.newHashSet(); private MultiMap myBlocksToForceChildrenIndent = new LinkedMultiMap(); - private Map myMarkerIndentToBlock = ContainerUtil.newHashMap(); private InitialInfoBuilder(final Block rootBlock, final FormattingDocumentModel model, @@ -294,11 +292,7 @@ class InitialInfoBuilder { public MultiMap getExpandableIndentsBlocks() { return myBlocksToForceChildrenIndent; } - - public Map getMarkerBlocks() { - return myMarkerIndentToBlock; - } - + private void doIteration(@NotNull State state) { List subBlocks = state.parentBlock.getSubBlocks(); final int subBlocksCount = subBlocks.size(); @@ -338,17 +332,9 @@ class InitialInfoBuilder { } private void registerExpandableIndents(@NotNull Block block, @NotNull AbstractBlockWrapper wrapper) { - ExpandableIndent expandableIndent = block.getIndent() instanceof ExpandableIndent ? ((ExpandableIndent)block.getIndent()) : null; - if (expandableIndent != null) { - myBlocksToForceChildrenIndent.putValue(expandableIndent, wrapper); - Block markerBlock = expandableIndent.getStrictMinOffsetBlock(); - if (markerBlock != null) { - myStrictMinOffsetBlocks.add(markerBlock); - } - } - - if (myStrictMinOffsetBlocks.contains(block)) { - myMarkerIndentToBlock.put(block, wrapper); + if (block.getIndent() instanceof ExpandableIndent) { + ExpandableIndent indent = (ExpandableIndent)block.getIndent(); + myBlocksToForceChildrenIndent.putValue(indent, wrapper); } } From 9428be03b416ac5f9e2bac8044e553d3de754dcc Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 10:26:41 +0200 Subject: [PATCH 12/27] cleanup --- platform/configuration-store-impl/src/ComponentStoreImpl.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index be72f34d9085..2921901b5308 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -240,10 +240,9 @@ abstract class ComponentStoreImpl : IComponentStore { val defaultState = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null val storageSpecs = getStorageSpecs(component, stateSpec, StateStorageOperation.READ) - val stateStorageChooser = component as? StateStorageChooserEx + val storageChooser = component as? StateStorageChooserEx for (storageSpec in storageSpecs) { - val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ) - if (resolution === Resolution.SKIP) { + if (storageChooser?.getResolution(storageSpec, StateStorageOperation.READ) == Resolution.SKIP) { continue } From de241251c83efbd117b34bc03e9829e1d870b180 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 11:42:13 +0200 Subject: [PATCH 13/27] don't apply "don't save if only format is changed --- .../src/ComponentStoreImpl.kt | 12 ++++++++-- .../src/DirectoryBasedStorage.kt | 2 +- .../src/ProjectStoreImpl.kt | 2 ++ .../src/StorageBaseEx.kt | 9 +++----- .../src/XmlElementStorage.kt | 2 +- .../testSrc/ApplicationStoreTest.kt | 23 ++++++++++++++++++- .../testSrc/XmlElementStorageTest.kt | 4 ++-- .../roots/impl/storage/ClasspathStorage.java | 2 +- .../impl/stores/StateStorageBase.kt | 10 +++++--- 9 files changed, 49 insertions(+), 17 deletions(-) diff --git a/platform/configuration-store-impl/src/ComponentStoreImpl.kt b/platform/configuration-store-impl/src/ComponentStoreImpl.kt index 2921901b5308..dcd128e91820 100644 --- a/platform/configuration-store-impl/src/ComponentStoreImpl.kt +++ b/platform/configuration-store-impl/src/ComponentStoreImpl.kt @@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util import com.intellij.openapi.util.* import com.intellij.openapi.util.Pair +import com.intellij.openapi.util.registry.Registry import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess import com.intellij.util.ArrayUtilRt @@ -247,7 +248,7 @@ abstract class ComponentStoreImpl : IComponentStore { } val storage = storageManager.getStateStorage(storageSpec) - var stateGetter = (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) + var stateGetter = if (isUseLoadedStateAsExisting(storageSpec) && Registry.`is`("use.loaded.state.as.existing", false)) (storage as? StorageBaseEx<*>)?.createGetSession(component, name, stateClass) else null var state = if (stateGetter == null) storage.getState(component, name, stateClass, defaultState, reloadData) else stateGetter.getState(defaultState) if (state == null) { if (changedStorages != null && changedStorages.contains(storage)) { @@ -260,7 +261,12 @@ abstract class ComponentStoreImpl : IComponentStore { } } - stateGetter?.use { component.loadState(state) } + try { + component.loadState(state) + } + finally { + stateGetter?.close() + } return name } @@ -270,6 +276,8 @@ abstract class ComponentStoreImpl : IComponentStore { return name } + protected open fun isUseLoadedStateAsExisting(storageSpec: Storage): Boolean = true + protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null private fun getDefaultState(component: Any, componentName: String, stateClass: Class): T? { diff --git a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt index c31da745fab6..cf7dc58e7166 100644 --- a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt +++ b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt @@ -62,7 +62,7 @@ open class DirectoryBasedStorage(private val myPathMacroSubstitutor: TrackingPat } } - override fun getState(storageData: Map, component: Any?, componentName: String) = getCompositeStateAndArchive(storageData, componentName, mySplitter) + override fun getState(storageData: Map, component: Any?, componentName: String, archive: Boolean) = getCompositeStateAndArchive(storageData, componentName, mySplitter) override fun loadData(): MutableMap { return fromMap(DirectoryStorageUtil.loadFrom(getVirtualFile(), myPathMacroSubstitutor)) diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 5ca7c61f9f6c..f3a5128b3aa6 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -288,6 +288,8 @@ open class ProjectStoreImpl(override val project: ProjectImpl, private val pathM } override fun selectDefaultStorages(storages: Array, operation: StateStorageOperation) = selectDefaultStorages(storages, operation, scheme) + + override fun isUseLoadedStateAsExisting(storageSpec: Storage) = storageSpec.file != StoragePathMacros.WORKSPACE_FILE } fun selectDefaultStorages(storages: Array, operation: StateStorageOperation, scheme: StorageScheme): Array { diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 217b257d5f35..0266f17b5155 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -15,12 +15,9 @@ */ package com.intellij.configurationStore -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.components.impl.stores.StateStorageBase -import com.intellij.openapi.util.registry.Registry import org.jdom.Element -import java.io.Closeable abstract class StorageBaseEx : StateStorageBase() { fun createGetSession(component: PersistentStateComponent, componentName: String, stateClass: Class, reload: Boolean = false) = StateGetter(component, componentName, getStorageData(reload), stateClass, this) @@ -31,7 +28,7 @@ abstract class StorageBaseEx : StateStorageBase() { abstract fun archiveState(storageData: T, componentName: String, serializedState: Element?) } -class StateGetter(private val component: PersistentStateComponent, private val componentName: String, private val storageData: T, private val stateClass: Class, private val storage: StorageBaseEx) : Closeable { +class StateGetter(private val component: PersistentStateComponent, private val componentName: String, private val storageData: T, private val stateClass: Class, private val storage: StorageBaseEx) { var serializedState: Element? = null fun getState(mergeInto: S? = null): S? { @@ -44,7 +41,7 @@ class StateGetter(private val component: PersistentStateCompon return storage.deserializeState(serializedState, stateClass, mergeInto) } - override fun close() { + fun close() { if (serializedState == null) { return } @@ -53,7 +50,7 @@ class StateGetter(private val component: PersistentStateCompon val stateAfterLoad: S? try { - stateAfterLoad = if (ApplicationManager.getApplication().isUnitTestMode() || Registry.`is`("use.loaded.state.as.existing", false)) component.getState() else null + stateAfterLoad = component.getState() } catch(e: Throwable) { LOG.error("Cannot get state after load", e) diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index 67bed1a75dac..d5a6f05e5c28 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -37,7 +37,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S protected abstract fun loadLocalData(): Element? - override final fun getState(storageData: StateMap, component: Any?, componentName: String) = storageData.getState(componentName) + override final fun getState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName) override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) { storageData.archive(componentName, serializedState) diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 5e5c5d89d58d..66bf4c5dced3 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -110,7 +110,7 @@ class ApplicationStoreTest { } @State(name = "A", storages = arrayOf(Storage(file = "a.xml"))) - private class A : PersistentStateComponent { + private open class A : PersistentStateComponent { data class State(@Attribute var foo: String = "", @Attribute var bar: String = "") var state = State() @@ -144,6 +144,24 @@ class ApplicationStoreTest { assertThat(file).hasContent("\n \n") } + @Test fun `don't apply "don't save if only format is changed" logic to workspace storage`() { + @State(name = "A", storages = arrayOf(Storage(file = StoragePathMacros.WORKSPACE_FILE))) + class AWorkspace : A() + + val oldContent = "" + val file = writeConfig("workspace.xml", oldContent) + val oldModificationTime = file.getLastModifiedTime() + testAppConfig.refreshVfs() + + val component = AWorkspace() + componentStore.initComponent(component, false) + assertThat(component.state).isEqualTo(A.State("old")) + + saveStore() + + assertThat(file).hasContent("\n \n") + } + private fun saveStore() { runInEdtAndWait { componentStore.save(SmartList()) } } @@ -188,7 +206,10 @@ class ApplicationStoreTest { override fun setPath(path: String) { storageManager.addMacro(StoragePathMacros.APP_CONFIG, path) + storageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, "$path/workspace.xml") } + + override fun isUseLoadedStateAsExisting(storageSpec: Storage) = storageSpec.file != StoragePathMacros.WORKSPACE_FILE } abstract class Foo { diff --git a/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt b/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt index ad55501e98c5..d31a37ac7e95 100644 --- a/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt +++ b/platform/configuration-store-impl/testSrc/XmlElementStorageTest.kt @@ -24,7 +24,7 @@ import org.junit.Test class XmlElementStorageTest { @Test fun testGetStateSucceeded() { val storage = MyXmlElementStorage(tag("root", tag("component", attr("name", "test"), tag("foo")))) - val state = storage.getState(this, "test", javaClass(), null, false) + val state = storage.getState(this, "test", javaClass()) assertThat(state).isNotNull() assertThat(state!!.getName()).isEqualTo("component") assertThat(state.getChild("foo")).isNotNull() @@ -32,7 +32,7 @@ class XmlElementStorageTest { @Test fun `get state not succeeded`() { val storage = MyXmlElementStorage(tag("root")) - val state = storage.getState(this, "test", javaClass(), null, false) + val state = storage.getState(this, "test", javaClass()) assertThat(state).isNull() } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java index 7b07acf493ce..47bd6ed0a415 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java @@ -135,7 +135,7 @@ public class ClasspathStorage extends StateStorageBase { @Nullable @Override - public Element getState(@NotNull Boolean storageData, Object component, @NotNull String componentName) { + public Element getState(@NotNull Boolean storageData, Object component, @NotNull String componentName, boolean archive) { if (storageData) { return null; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt index 0223a27d6ce8..39e513cf442b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt @@ -29,15 +29,19 @@ public abstract class StateStorageBase : StateStorage { protected val storageDataRef: AtomicReference = AtomicReference() - override fun getState(component: Any?, componentName: String, stateClass: Class, mergeInto: S?, reload: Boolean): S? { - return deserializeState(getState(getStorageData(reload), component, componentName), stateClass, mergeInto) + override final fun getState(component: Any?, componentName: String, stateClass: Class, mergeInto: S?, reload: Boolean): S? { + return getState(component, componentName, stateClass, true, reload, mergeInto) + } + + fun getState(component: Any?, componentName: String, stateClass: Class, archive: Boolean = true, reload: Boolean = false, mergeInto: S? = null): S? { + return deserializeState(getState(getStorageData(reload), component, componentName, archive), stateClass, mergeInto) } open fun deserializeState(serializedState: Element?, stateClass: Class, mergeInto: S?): S? { return DefaultStateSerializer.deserializeState(serializedState, stateClass, mergeInto) } - abstract fun getState(storageData: T, component: Any?, componentName: String): Element? + abstract fun getState(storageData: T, component: Any?, componentName: String, archive: Boolean = true): Element? protected abstract fun hasState(storageData: T, componentName: String): Boolean From 33eef709cbe3e835437e5bd54a56f334fcb70698 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 11:57:32 +0200 Subject: [PATCH 14/27] fix test name to avoid win issues --- .../configuration-store-impl/testSrc/ApplicationStoreTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt index 66bf4c5dced3..2120a265f162 100644 --- a/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt +++ b/platform/configuration-store-impl/testSrc/ApplicationStoreTest.kt @@ -144,7 +144,7 @@ class ApplicationStoreTest { assertThat(file).hasContent("\n \n") } - @Test fun `don't apply "don't save if only format is changed" logic to workspace storage`() { + @Test fun `do not apply to workspace storage - do not save if only format is changed`() { @State(name = "A", storages = arrayOf(Storage(file = StoragePathMacros.WORKSPACE_FILE))) class AWorkspace : A() From 52b198060a8613e718e91d6c4e693036bace03dd Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 2 Sep 2015 13:01:40 +0300 Subject: [PATCH 15/27] IDEA-144638 the code coverage gutter indicator overlaps with gutter icon and is impossible to click --- .../editor/ex/EditorGutterComponentEx.java | 2 + .../impl/EditorGutterComponentImpl.java | 90 +++++++++++-------- .../editor/markup/LineMarkerRendererEx.java | 30 +++++++ .../coverage/CoverageLineMarkerRenderer.java | 33 +++++-- 4 files changed, 115 insertions(+), 40 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/editor/markup/LineMarkerRendererEx.java diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java index 4926fc4b9e2c..38c8290cea6f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java @@ -52,6 +52,8 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit public abstract int getLineMarkerAreaOffset(); + public abstract int getIconAreaOffset(); + public abstract int getLineMarkerFreePaintersAreaOffset(); public abstract int getIconsAreaWidth(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 7865d0877b9c..2cca0857a059 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -82,8 +82,9 @@ import java.util.List; class EditorGutterComponentImpl extends EditorGutterComponentEx implements MouseListener, MouseMotionListener, DataProvider { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.EditorGutterComponentImpl"); private static final int START_ICON_AREA_WIDTH = 15; - private static final int FREE_PAINTERS_AREA_WIDTH = 5; - private static final int GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA = 5; + private static final int FREE_PAINTERS_LEFT_AREA_WIDTH = 8; + private static final int FREE_PAINTERS_RIGHT_AREA_WIDTH = 5; + private static final int GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA = 5; private static final int GAP_BETWEEN_ICONS = 3; private static final int GAP_BEFORE_LINE_NUMBERS = 5; private static final int GAP_AFTER_LINE_NUMBERS = 4; @@ -97,7 +98,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private final EditorImpl myEditor; private final FoldingAnchorsOverlayStrategy myAnchorsDisplayStrategy; - private int myLineMarkerAreaWidth = START_ICON_AREA_WIDTH + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA + FREE_PAINTERS_AREA_WIDTH; private int myIconsAreaWidth = START_ICON_AREA_WIDTH; private int myLineNumberAreaWidth = 0; private int myAdditionalLineNumberAreaWidth = 0; @@ -116,6 +116,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse @Nullable private ActionGroup myCustomGutterPopupGroup; private TIntObjectHashMap myTextFgColors = new TIntObjectHashMap(); private boolean myPaintBackground = true; + private boolean myLeftFreePaintersAreaShown; @SuppressWarnings("unchecked") public EditorGutterComponentImpl(EditorImpl editor) { @@ -629,14 +630,14 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private void updateSizeInner(boolean onLayout) { if (!onLayout) { calcLineNumberAreaWidth(); - calcIconAreaWidth(); + calcLineMarkerAreaWidth(); calcAnnotationsSize(); } calcAnnotationExtraSize(); } private int sizeHash() { - int result = myLineMarkerAreaWidth; + int result = getLineMarkerAreaWidth(); result = 31 * result + myTextAnnotationGuttersSize; result = 31 * result + myTextAnnotationExtraSize; result = 31 * result + getLineNumberAreaWidth(); @@ -682,19 +683,27 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse int width = editorLocationX + editorComponent.getWidth(); if (rightMarginX < width && editorLocationX < width - rightMarginX) { - int centeredSize = (width - rightMarginX - editorLocationX) / 2 - (myLineMarkerAreaWidth + getLineNumberAreaWidth()); + int centeredSize = (width - rightMarginX - editorLocationX) / 2 - (getLineMarkerAreaWidth() + getLineNumberAreaWidth()); myTextAnnotationExtraSize = Math.max(0, centeredSize - myTextAnnotationGuttersSize); } } private TIntObjectHashMap> myLineToGutterRenderers; - private void calcIconAreaWidth() { + private void calcLineMarkerAreaWidth() { myLineToGutterRenderers = new TIntObjectHashMap>(); + myLeftFreePaintersAreaShown = false; processRangeHighlighters(0, myEditor.getDocument().getTextLength(), new RangeHighlighterProcessor() { @Override public void process(@NotNull RangeHighlighter highlighter) { + LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer(); + if (lineMarkerRenderer instanceof LineMarkerRendererEx && + ((LineMarkerRendererEx)lineMarkerRenderer).getPosition() == LineMarkerRendererEx.Position.LEFT && + isLineMarkerVisible(highlighter)) { + myLeftFreePaintersAreaShown = true; + } + GutterMark renderer = highlighter.getGutterIconRenderer(); if (renderer == null) { return; @@ -734,8 +743,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return true; } }); - - myLineMarkerAreaWidth = myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA + FREE_PAINTERS_AREA_WIDTH; } private boolean isHighlighterVisible(RangeHighlighter highlighter) { @@ -791,28 +798,30 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } private void paintLineMarkerRenderer(RangeHighlighter highlighter, Graphics g) { - Rectangle rectangle = getLineRendererRectangle(highlighter); - - if (rectangle != null) { - final LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer(); - assert lineMarkerRenderer != null; - lineMarkerRenderer.paint(myEditor, g, rectangle); + LineMarkerRenderer lineMarkerRenderer = highlighter.getLineMarkerRenderer(); + if (lineMarkerRenderer != null) { + Rectangle rectangle = getLineRendererRectangle(highlighter); + if (rectangle != null) { + lineMarkerRenderer.paint(myEditor, g, rectangle); + } } } - - @Nullable - private Rectangle getLineRendererRectangle(RangeHighlighter highlighter) { - LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer(); - if (renderer == null) return null; - + + private boolean isLineMarkerVisible(RangeHighlighter highlighter) { int startOffset = highlighter.getStartOffset(); int endOffset = highlighter.getEndOffset(); FoldRegion startFoldRegion = myEditor.getFoldingModel().getCollapsedRegionAtOffset(startOffset); FoldRegion endFoldRegion = myEditor.getFoldingModel().getCollapsedRegionAtOffset(endOffset); - if (startFoldRegion != null && endFoldRegion != null && startFoldRegion.equals(endFoldRegion)) { - return null; - } + return startFoldRegion == null || endFoldRegion == null || !startFoldRegion.equals(endFoldRegion); + } + + @Nullable + private Rectangle getLineRendererRectangle(RangeHighlighter highlighter) { + if (!isLineMarkerVisible(highlighter)) return null; + + int startOffset = highlighter.getStartOffset(); + int endOffset = highlighter.getEndOffset(); int startY = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset)).y; @@ -825,9 +834,13 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse endY += myEditor.getLineHeight(); } + LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer(); + boolean leftPosition = renderer instanceof LineMarkerRendererEx && + ((LineMarkerRendererEx)renderer).getPosition() == LineMarkerRendererEx.Position.LEFT; + int height = endY - startY; - int w = FREE_PAINTERS_AREA_WIDTH; - int x = getLineMarkerFreePaintersAreaOffset() - 1; + int w = leftPosition ? FREE_PAINTERS_LEFT_AREA_WIDTH : FREE_PAINTERS_RIGHT_AREA_WIDTH; + int x = leftPosition ? getLineMarkerAreaOffset() : getLineMarkerFreePaintersAreaOffset() - 1; return new Rectangle(x, startY, w, height); } @@ -845,7 +858,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private void processIconsRow(int line, List row, LineGutterIconRendererProcessor processor) { int middleCount = 0; int middleSize = 0; - int x = getLineMarkerAreaOffset() + 2; + int x = getIconAreaOffset() + 2; final int y = myEditor.logicalPositionToXY(new LogicalPosition(line, 0)).y; for (GutterMark r : row) { @@ -862,9 +875,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - final int leftSize = x - getLineMarkerAreaOffset(); + final int leftSize = x - getIconAreaOffset(); - x = getLineMarkerAreaOffset() + myIconsAreaWidth - 2; // because of 2px LineMarkerRenderers + x = getIconAreaOffset() + myIconsAreaWidth - 2; // because of 2px LineMarkerRenderers for (GutterMark r : row) { if (!checkDumbAware(r, myEditor.getProject())) continue; if (((GutterIconRenderer)r).getAlignment() == GutterIconRenderer.Alignment.RIGHT) { @@ -875,11 +888,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - int rightSize = myIconsAreaWidth + getLineMarkerAreaOffset() - x + 1; + int rightSize = myIconsAreaWidth + getIconAreaOffset() - x + 1; if (middleCount > 0) { middleSize -= GAP_BETWEEN_ICONS; - x = getLineMarkerAreaOffset() + leftSize + (myIconsAreaWidth - leftSize - rightSize - middleSize) / 2; + x = getIconAreaOffset() + leftSize + (myIconsAreaWidth - leftSize - rightSize - middleSize) / 2; for (GutterMark r : row) { if (!checkDumbAware(r, myEditor.getProject())) continue; if (((GutterIconRenderer)r).getAlignment() == GutterIconRenderer.Alignment.CENTER) { @@ -1121,7 +1134,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } public int getLineMarkerAreaWidth() { - return isLineMarkersShown() ? myLineMarkerAreaWidth : 0; + return isLineMarkersShown() ? ((myLeftFreePaintersAreaShown ? FREE_PAINTERS_LEFT_AREA_WIDTH : 0) + + myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA + FREE_PAINTERS_RIGHT_AREA_WIDTH) : + 0; } public void setLineNumberAreaWidthFunction(@NotNull TIntFunction calculator) { @@ -1200,9 +1215,14 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return getAnnotationsAreaOffset() + getAnnotationsAreaWidthEx(); } + @Override + public int getIconAreaOffset() { + return getLineMarkerAreaOffset() + (myLeftFreePaintersAreaShown ? FREE_PAINTERS_LEFT_AREA_WIDTH : 0); + } + @Override public int getLineMarkerFreePaintersAreaOffset() { - return getLineMarkerAreaOffset() + myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_FREE_PAINTERS_AREA; + return getIconAreaOffset() + myIconsAreaWidth + GAP_BETWEEN_ICONS_AND_RIGHT_FREE_PAINTERS_AREA; } @Override @@ -1466,7 +1486,8 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse processRangeHighlighters(firstVisibleOffset, lastVisibleOffset, new RangeHighlighterProcessor() { @Override public void process(@NotNull RangeHighlighter highlighter) { - if (gutterRenderer[0] != null) return; + LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer(); + if (renderer == null || gutterRenderer[0] != null) return; Rectangle rectangle = getLineRendererRectangle(highlighter); if (rectangle == null) return; @@ -1477,7 +1498,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } if (startY < e.getY() && e.getY() <= endY) { - final LineMarkerRenderer renderer = highlighter.getLineMarkerRenderer(); if (renderer instanceof ActiveGutterRenderer && ((ActiveGutterRenderer)renderer).canDoAction(e)) { gutterRenderer[0] = (ActiveGutterRenderer)renderer; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/markup/LineMarkerRendererEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/markup/LineMarkerRendererEx.java new file mode 100644 index 000000000000..51f830b56c43 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/markup/LineMarkerRendererEx.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.markup; + +import com.intellij.openapi.editor.Editor; + +import java.awt.*; + +public interface LineMarkerRendererEx extends LineMarkerRenderer { + enum Position {LEFT, RIGHT} + + /** + * Determines whether line marker should be rendered to the left or to the right of icon area in gutter. + * Corresponding rectangle will be passed to renderer in {@link #paint(Editor, Graphics, Rectangle)} method. + */ + Position getPosition(); +} diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageLineMarkerRenderer.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageLineMarkerRenderer.java index e25e82570cd9..190c35bf46d3 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageLineMarkerRenderer.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageLineMarkerRenderer.java @@ -1,5 +1,17 @@ /* - * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved. + * Copyright 2000-2015 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.coverage; @@ -25,6 +37,7 @@ import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.EditorGutterComponentEx; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.markup.ActiveGutterRenderer; +import com.intellij.openapi.editor.markup.LineMarkerRendererEx; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SearchableConfigurable; @@ -57,7 +70,7 @@ import java.util.TreeMap; /** * @author ven */ -public class CoverageLineMarkerRenderer implements ActiveGutterRenderer { +public class CoverageLineMarkerRenderer implements LineMarkerRendererEx, ActiveGutterRenderer { private static final int THICKNESS = 8; private final TextAttributesKey myKey; private final String myClassName; @@ -97,10 +110,10 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer { if (bgColor != null) { g.setColor(bgColor); } - g.fillRect(0, r.y, THICKNESS, r.height); + g.fillRect(r.x, r.y, r.width, r.height); final LineData lineData = getLineData(editor.xyToLogicalPosition(new Point(0, r.y)).line); if (lineData != null && lineData.isCoveredByOneTest()) { - g.drawImage( ImageLoader.loadFromResource("/gutter/unique.png"), 0, r.y, 8, 8, editor.getComponent()); + g.drawImage( ImageLoader.loadFromResource("/gutter/unique.png"), r.x, r.y, 8, 8, editor.getComponent()); } } @@ -135,7 +148,12 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer { } public boolean canDoAction(final MouseEvent e) { - return e.getX() < THICKNESS; + Component component = e.getComponent(); + if (component instanceof EditorGutterComponentEx) { + EditorGutterComponentEx gutter = (EditorGutterComponentEx)component; + return e.getX() > gutter.getLineMarkerAreaOffset() && e.getX() < gutter.getIconAreaOffset(); + } + return false; } public void doAction(final Editor editor, final MouseEvent e) { @@ -253,6 +271,11 @@ public class CoverageLineMarkerRenderer implements ActiveGutterRenderer { return editor.getColorsScheme().getAttributes(myKey).getErrorStripeColor(); } + @Override + public Position getPosition() { + return Position.LEFT; + } + private class GotoPreviousCoveredLineAction extends BaseGotoCoveredLineAction { public GotoPreviousCoveredLineAction(final Editor editor, final int lineNumber) { From 098d3e1d432c210fd62b104b402c698978454e26 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 12:18:20 +0200 Subject: [PATCH 16/27] =?UTF-8?q?clarify=20method=20name=20=E2=80=94=20ren?= =?UTF-8?q?ame=20to=20getSerializedState?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration-store-impl/src/DirectoryBasedStorage.kt | 2 +- platform/configuration-store-impl/src/StorageBaseEx.kt | 8 ++++++-- .../configuration-store-impl/src/XmlElementStorage.kt | 2 +- .../openapi/roots/impl/storage/ClasspathStorage.java | 2 +- .../openapi/components/impl/stores/StateStorageBase.kt | 8 +++----- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt index cf7dc58e7166..624f0b2bcfda 100644 --- a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt +++ b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt @@ -62,7 +62,7 @@ open class DirectoryBasedStorage(private val myPathMacroSubstitutor: TrackingPat } } - override fun getState(storageData: Map, component: Any?, componentName: String, archive: Boolean) = getCompositeStateAndArchive(storageData, componentName, mySplitter) + override fun getSerializedState(storageData: Map, component: Any?, componentName: String, archive: Boolean) = getCompositeStateAndArchive(storageData, componentName, mySplitter) override fun loadData(): MutableMap { return fromMap(DirectoryStorageUtil.loadFrom(getVirtualFile(), myPathMacroSubstitutor)) diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 0266f17b5155..ffed4fad4cf5 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -28,13 +28,17 @@ abstract class StorageBaseEx : StateStorageBase() { abstract fun archiveState(storageData: T, componentName: String, serializedState: Element?) } -class StateGetter(private val component: PersistentStateComponent, private val componentName: String, private val storageData: T, private val stateClass: Class, private val storage: StorageBaseEx) { +class StateGetter(private val component: PersistentStateComponent, + private val componentName: String, + private val storageData: T, + private val stateClass: Class, + private val storage: StorageBaseEx) { var serializedState: Element? = null fun getState(mergeInto: S? = null): S? { LOG.assertTrue(serializedState == null) - serializedState = storage.getState(storageData, component, componentName) + serializedState = storage.getSerializedState(storageData, component, componentName, false) if (serializedState != null) { //System.out.println("open $componentName to read state, ${hashCode()} $storage, ${Thread.currentThread()}") } diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index d5a6f05e5c28..8d41a8848cf7 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -37,7 +37,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S protected abstract fun loadLocalData(): Element? - override final fun getState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName) + override final fun getSerializedState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName) override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) { storageData.archive(componentName, serializedState) diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java index 47bd6ed0a415..60f3145f8764 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java @@ -135,7 +135,7 @@ public class ClasspathStorage extends StateStorageBase { @Nullable @Override - public Element getState(@NotNull Boolean storageData, Object component, @NotNull String componentName, boolean archive) { + public Element getSerializedState(@NotNull Boolean storageData, Object component, @NotNull String componentName, boolean archive) { if (storageData) { return null; } diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt index 39e513cf442b..08c0ddafc8e6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt @@ -34,14 +34,14 @@ public abstract class StateStorageBase : StateStorage { } fun getState(component: Any?, componentName: String, stateClass: Class, archive: Boolean = true, reload: Boolean = false, mergeInto: S? = null): S? { - return deserializeState(getState(getStorageData(reload), component, componentName, archive), stateClass, mergeInto) + return deserializeState(getSerializedState(getStorageData(reload), component, componentName, archive), stateClass, mergeInto) } open fun deserializeState(serializedState: Element?, stateClass: Class, mergeInto: S?): S? { return DefaultStateSerializer.deserializeState(serializedState, stateClass, mergeInto) } - abstract fun getState(storageData: T, component: Any?, componentName: String, archive: Boolean = true): Element? + abstract fun getSerializedState(storageData: T, component: Any?, componentName: String, archive: Boolean = true): Element? protected abstract fun hasState(storageData: T, componentName: String): Boolean @@ -49,9 +49,7 @@ public abstract class StateStorageBase : StateStorage { return hasState(getStorageData(reloadData), componentName) } - public fun getStorageData(): T { - return getStorageData(false) - } + public fun getStorageData(): T = getStorageData(false) protected fun getStorageData(reload: Boolean): T { val storageData = storageDataRef.get() From d1b6d0499bbd90398ea83e74fb110057fbbb79bc Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 12:26:16 +0200 Subject: [PATCH 17/27] cleanup LOG usage --- platform/configuration-store-impl/src/DirectoryBasedStorage.kt | 2 +- .../intellij/openapi/roots/impl/storage/ClasspathStorage.java | 3 +++ .../openapi/components/impl/stores/StateStorageBase.kt | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt index 624f0b2bcfda..75b0933332bb 100644 --- a/platform/configuration-store-impl/src/DirectoryBasedStorage.kt +++ b/platform/configuration-store-impl/src/DirectoryBasedStorage.kt @@ -174,7 +174,7 @@ open class DirectoryBasedStorage(private val myPathMacroSubstitutor: TrackingPat writeFile(null, this, file, storeElement, LineSeparator.fromString(if (file.exists()) loadFile(file).second else SystemProperties.getLineSeparator()), false) } catch (e: IOException) { - StateStorageBase.LOG.error(e) + LOG.error(e) } finally { if (element != null) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java index 60f3145f8764..c94202d6f927 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java @@ -25,6 +25,7 @@ import com.intellij.openapi.components.TrackingPathMacroSubstitutor; import com.intellij.openapi.components.impl.stores.StateStorageBase; import com.intellij.openapi.components.impl.stores.StateStorageManager; import com.intellij.openapi.components.impl.stores.StorageManagerListener; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootModel; @@ -55,6 +56,8 @@ import java.util.Set; // Boolean - false as not loaded, true as loaded public class ClasspathStorage extends StateStorageBase { + private static final Logger LOG = Logger.getInstance(ClasspathStorage.class); + @NonNls public static final String SPECIAL_STORAGE = "special"; private final ClasspathStorageProvider.ClasspathConverter myConverter; diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt index 08c0ddafc8e6..5f2d9556f819 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageBase.kt @@ -22,7 +22,7 @@ import java.util.concurrent.atomic.AtomicReference public abstract class StateStorageBase : StateStorage { companion object { - protected val LOG: Logger = Logger.getInstance(javaClass>()) + private val LOG: Logger = Logger.getInstance(javaClass>()) } private var mySavingDisabled = false From 613d54d53f74344e2fd6ec29bfdd44eb946585de Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 2 Sep 2015 12:34:39 +0200 Subject: [PATCH 18/27] continue "don't save if only format is changed" --- platform/configuration-store-impl/src/StateMap.kt | 11 +++++++---- .../configuration-store-impl/src/XmlElementStorage.kt | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/configuration-store-impl/src/StateMap.kt b/platform/configuration-store-impl/src/StateMap.kt index b90b8d5b815f..93a11d6deafa 100644 --- a/platform/configuration-store-impl/src/StateMap.kt +++ b/platform/configuration-store-impl/src/StateMap.kt @@ -122,8 +122,6 @@ class StateMap private constructor(private val names: Array, private val fun isEmpty() = names.isEmpty() - fun getState(key: String) = get(key) as? Element - fun hasState(key: String) = get(key) is Element public fun hasStates(): Boolean { @@ -152,14 +150,19 @@ class StateMap private constructor(private val names: Array, private val } } - public fun getStateAndArchive(key: String): Element? { + fun getStateAndArchive(key: String) = getState(key, true) + + fun getState(key: String, archive: Boolean = false): Element? { val index = Arrays.binarySearch(names, key) if (index < 0) { return null } val state = states.get(index) as? Element ?: return null - return if (states.compareAndSet(index, state, archiveState(state))) state else getStateAndArchive(key) + if (!archive) { + return state + } + return if (states.compareAndSet(index, state, archiveState(state))) state else getState(key, true) } public fun archive(key: String, state: Element?) { diff --git a/platform/configuration-store-impl/src/XmlElementStorage.kt b/platform/configuration-store-impl/src/XmlElementStorage.kt index 8d41a8848cf7..8d16a69a9585 100644 --- a/platform/configuration-store-impl/src/XmlElementStorage.kt +++ b/platform/configuration-store-impl/src/XmlElementStorage.kt @@ -37,7 +37,7 @@ abstract class XmlElementStorage protected constructor(protected val fileSpec: S protected abstract fun loadLocalData(): Element? - override final fun getSerializedState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName) + override final fun getSerializedState(storageData: StateMap, component: Any?, componentName: String, archive: Boolean) = storageData.getState(componentName, archive) override fun archiveState(storageData: StateMap, componentName: String, serializedState: Element?) { storageData.archive(componentName, serializedState) From 96b5644ba79ab61947b1093bf4e7be35651849ef Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Tue, 1 Sep 2015 18:05:33 +0200 Subject: [PATCH 19/27] #WEB-17998 fixed --- xml/xml-psi-impl/src/com/intellij/xml/util/HtmlControls.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlControls.xml b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlControls.xml index 88edfb5bd1f3..290e85f5a6fe 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlControls.xml +++ b/xml/xml-psi-impl/src/com/intellij/xml/util/HtmlControls.xml @@ -115,7 +115,7 @@ - + From 3a927cc6f59b1505b7455290d59598c93c6b3b4b Mon Sep 17 00:00:00 2001 From: Pavel Fatin Date: Tue, 1 Sep 2015 20:17:37 +0200 Subject: [PATCH 20/27] Zero-latency typing: enable for a first char in document --- .../ex/util/LexerEditorHighlighter.java | 36 ++++++++++--------- .../openapi/editor/impl/EditorImpl.java | 1 - 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java index 67e3ea3952de..8d12bfe863a9 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/ex/util/LexerEditorHighlighter.java @@ -360,24 +360,28 @@ public class LexerEditorHighlighter implements EditorHighlighter, PrioritizedDoc // Called to determine visual attributes of inserted character prior to starting a write action. // TODO Should be removed when we implement typing without starting write actions. public TextAttributes getAttributes(DocumentImpl document, int offset, char c) { - final int segmentIndex; - try { - segmentIndex = mySegments.findSegmentIndex(offset) - 2; - } - catch (IndexOutOfBoundsException ex) { - throw new IndexOutOfBoundsException(ex.getMessage() + " Lexer: " + myLexer); - } - int startIndex = Math.max(0, segmentIndex); + int startOffset = 0; - int data; - do { - data = mySegments.getSegmentData(startIndex); - if (isInitialState(data)|| startIndex == 0) break; - startIndex--; - } - while (true); + if (mySegments.getSegmentCount() > 0) { + final int segmentIndex; + try { + segmentIndex = mySegments.findSegmentIndex(offset) - 2; + } + catch (IndexOutOfBoundsException ex) { + throw new IndexOutOfBoundsException(ex.getMessage() + " Lexer: " + myLexer); + } + int startIndex = Math.max(0, segmentIndex); - int startOffset = mySegments.getSegmentStart(startIndex); + int data; + do { + data = mySegments.getSegmentData(startIndex); + if (isInitialState(data)|| startIndex == 0) break; + startIndex--; + } + while (true); + + startOffset = mySegments.getSegmentStart(startIndex); + } ImmutableText newText = document.getImmutableText().insert(offset, Character.toString(c)); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index a2ad202a5e87..f85b06a7c727 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2186,7 +2186,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi private boolean canPaintImmediately(char c) { return myDocument instanceof DocumentImpl && myHighlighter instanceof LexerEditorHighlighter && - myDocument.getTextLength() > 0 && !mySelectionModel.hasSelection() && areVisualLinesUnique(myCaretModel.getAllCarets()) && !isInplaceRenamerActive() && From d222f61d8e70c678bbb13c055ac6f58438c45007 Mon Sep 17 00:00:00 2001 From: Pavel Fatin Date: Tue, 1 Sep 2015 20:35:00 +0200 Subject: [PATCH 21/27] Zero-latency typing: improved font selection --- .../intellij/openapi/editor/impl/EditorImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index f85b06a7c727..c44e3ab1817a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2221,8 +2221,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi TextAttributes attributes = ((LexerEditorHighlighter)myHighlighter).getAttributes((DocumentImpl)myDocument, offset, c); int fontType = attributes.getFontType(); - Font font = fontFor(fontType); + FontInfo fontInfo = EditorUtil.fontForChar(c, attributes.getFontType(), this); + Font font = fontInfo.getFont(); + // it's more reliable to query actual font metrics FontMetrics fontMetrics = getFontMetrics(fontType); int charWidth = fontMetrics.charWidth(c); @@ -2317,7 +2319,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi Point point = newArea.getLocation(); int ascent = getAscent(); - Font font = fontFor(attributes.getFontType()); + // simplified font selection (based on the first character) + FontInfo fontInfo = EditorUtil.fontForChar(newText.charAt(0), attributes.getFontType(), this); + Font font = fontInfo.getFont(); + Color color = attributes.getForegroundColor() == null ? getForegroundColor() : attributes.getForegroundColor(); EditorUIUtil.setupAntialiasing(g); @@ -2349,11 +2354,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return color == null ? getBackgroundColor() : color; } - @NotNull - private Font fontFor(int fontType) { - return myScheme.getFont(EditorFontType.values()[fontType]); - } - private static void shift(@NotNull Graphics g, @NotNull Rectangle r, int delta) { g.copyArea(r.x, r.y, r.width, r.height, delta, 0); } From 4f22cc16f66226362ed582940bb44be75f4f9377 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 2 Sep 2015 13:56:39 +0300 Subject: [PATCH 22/27] IDEA-144666 Surround with runtime type doesn't work for array types --- .../JavaWithRuntimeCastSurrounder.java | 10 ++--- .../codeinsight/RuntimeTypeEvaluator.java | 37 ++++++++++--------- .../DefaultCodeFragmentFactory.java | 11 ++---- .../watch/DebuggerTreeNodeExpression.java | 5 ++- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java index 08cced8c51c4..0bb24ce60dee 100644 --- a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java +++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java @@ -71,7 +71,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { return null; } - private class SurroundWithCastWorker extends RuntimeTypeEvaluator { + private static class SurroundWithCastWorker extends RuntimeTypeEvaluator { private final Editor myEditor; public SurroundWithCastWorker(Editor editor, PsiExpression expression, DebuggerContextImpl context, final ProgressIndicator indicator) { @@ -80,7 +80,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { } @Override - protected void typeCalculationFinished(@Nullable final PsiClass type) { + protected void typeCalculationFinished(@Nullable final PsiType type) { if (type == null) { return; } @@ -94,9 +94,9 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { try { PsiElementFactory factory = JavaPsiFacade.getInstance(myElement.getProject()).getElementFactory(); PsiParenthesizedExpression parenth = - (PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getQualifiedName() + ")expr)", null); - PsiTypeCastExpression cast = (PsiTypeCastExpression)parenth.getExpression(); - cast.getOperand().replace(myElement); + (PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getCanonicalText() + ")expr)", null); + //noinspection ConstantConditions + ((PsiTypeCastExpression)parenth.getExpression()).getOperand().replace(myElement); parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth); PsiExpression expr = (PsiExpression)myElement.replace(parenth); TextRange range = expr.getTextRange(); diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java index ecb7556bf2c7..a3bf6ca1db11 100644 --- a/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 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. @@ -19,6 +19,7 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerInvocationUtil; import com.intellij.debugger.EvaluatingComputable; import com.intellij.debugger.engine.ContextUtil; +import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; @@ -33,7 +34,6 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.sun.jdi.ClassType; import com.sun.jdi.InterfaceType; import com.sun.jdi.Type; @@ -43,13 +43,13 @@ import org.jetbrains.annotations.Nullable; /** * @author peter */ -public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand { +public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand { public RuntimeTypeEvaluator(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context, final ProgressIndicator indicator) { super(editor, expression, context, indicator); } public void threadAction() { - PsiClass type = null; + PsiType type = null; try { type = evaluate(); } @@ -62,10 +62,10 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand() { @@ -82,36 +82,37 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand nameRef = new AtomicReference(); + final AtomicReference nameRef = new AtomicReference(); final RuntimeTypeEvaluator worker = new RuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().getProgressIndicator()) { @Override - protected void typeCalculationFinished(@Nullable PsiClass type) { + protected void typeCalculationFinished(@Nullable PsiType type) { nameRef.set(type); semaphore.up(); } @@ -106,10 +106,7 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory { ProgressManager.checkCanceled(); if (semaphore.waitFor(20)) break; } - final PsiClass psiClass = nameRef.get(); - if (psiClass != null) { - return JavaPsiFacade.getElementFactory(project).createType(psiClass); - } + return nameRef.get(); } return null; } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java index fea7faf504f9..73874ef9c0be 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java @@ -219,16 +219,17 @@ public class DebuggerTreeNodeExpression { Project project = expression.getProject(); - PsiClass type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value); + PsiType type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value); if (type == null) { return expression; } PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); - String typeName = type.getQualifiedName(); + String typeName = type.getCanonicalText(); try { PsiParenthesizedExpression parenthExpression = (PsiParenthesizedExpression)elementFactory.createExpressionFromText( "((" + typeName + ")expression)", null); + //noinspection ConstantConditions ((PsiTypeCastExpression)parenthExpression.getExpression()).getOperand().replace(expression); Set imports = expression.getUserData(ADDITIONAL_IMPORTS_KEY); if (imports == null) { From 00a08306e9c9b0c55bf12655244a800dc7cc5c70 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 2 Sep 2015 14:10:13 +0300 Subject: [PATCH 23/27] IDEA-143820 --- .../daemon/impl/GutterIconTooltipHelper.java | 8 ++-- .../psi/impl/FindSuperElementsHelper.java | 15 ++++--- .../daemon/impl/JavaLineMarkerProvider.java | 6 ++- .../codeInsight/daemon/impl/MarkerType.java | 45 +++++++++++++++++++ .../daemon/impl/JavaGotoSuperTest.java | 2 +- 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java index de09c0840340..780fd5886003 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 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,15 +36,15 @@ public class GutterIconTooltipHelper { private GutterIconTooltipHelper() { } - public static String composeText(@NotNull PsiElement[] elements, String start, final String pattern) { + public static String composeText(@NotNull PsiElement[] elements, @NotNull String start, @NotNull String pattern) { return composeText(Arrays.asList(elements), start, pattern); } - public static String composeText(@NotNull Iterable elements, String start, final String pattern) { + public static String composeText(@NotNull Iterable elements, @NotNull String start, @NotNull String pattern) { return composeText(elements, start, pattern, ""); } - public static String composeText(@NotNull Iterable elements, String start, final String pattern, String postfix) { + public static String composeText(@NotNull Iterable elements, @NotNull String start, @NotNull String pattern, @NotNull String postfix) { @NonNls StringBuilder result = new StringBuilder(); result.append(""); result.append(start); diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java index e9039aba119b..7d5bfda6dfec 100644 --- a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java +++ b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java @@ -15,6 +15,8 @@ */ package com.intellij.psi.impl; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.MethodSignature; @@ -64,11 +66,12 @@ public class FindSuperElementsHelper { } public static PsiMethod getSiblingInheritedViaSubClass(@NotNull PsiMethod method) { - return getSiblingInheritedViaSubClass(method, createSubClassCache()); + return Pair.getFirst(getSiblingInheritedViaSubClass(method, createSubClassCache())); } - public static PsiMethod getSiblingInheritedViaSubClass(@NotNull final PsiMethod method, - @NotNull Map subClassCache) { + // returns super method, sub class + public static Pair getSiblingInheritedViaSubClass(@NotNull final PsiMethod method, + @NotNull Map subClassCache) { if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null; if (method.hasModifierProperty(PsiModifier.STATIC)) return null; final PsiClass containingClass = method.getContainingClass(); @@ -77,7 +80,7 @@ public class FindSuperElementsHelper { return null; } final Collection checkedInterfaces = new THashSet(); - final PsiMethod[] result = new PsiMethod[1]; + final Ref> result = Ref.create(); ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(new Processor() { @Override public boolean process(PsiClass inheritor) { @@ -107,14 +110,14 @@ public class FindSuperElementsHelper { if (!isOverridden) { continue; } - result[0] = superMethod; + result.set(Pair.create(superMethod, inheritor)); return false; } } return true; } }); - return result[0]; + return result.get(); } @NotNull diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java index f60ba833b1f6..21847f82799c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java @@ -184,12 +184,14 @@ public class JavaLineMarkerProvider implements LineMarkerProvider { boolean canHaveSiblingSuper = !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC) && method.hasModifierProperty(PsiModifier.PUBLIC)&& !method.hasModifierProperty(PsiModifier.FINAL)&& !method.hasModifierProperty(PsiModifier.NATIVE); if (!canHaveSiblingSuper) continue; - PsiMethod siblingInheritedViaSubClass = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache); + PsiMethod siblingInheritedViaSubClass = Pair.getFirst(FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache)); if (siblingInheritedViaSubClass == null) { continue; } PsiElement range = getMethodRange(method); - LineMarkerInfo info = createSuperMethodLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, Pass.UPDATE_OVERRIDEN_MARKERS); + ArrowUpLineMarkerInfo upInfo = new ArrowUpLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, MarkerType.SIBLING_OVERRIDING_METHOD, + Pass.UPDATE_OVERRIDEN_MARKERS); + LineMarkerInfo info = NavigateAction.setNavigateAction(upInfo, "Go to super method", IdeActions.ACTION_GOTO_SUPER); result.add(info); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java index 5de455903a00..604e4db19817 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java @@ -33,8 +33,10 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.FindSuperElementsHelper; +import com.intellij.psi.presentation.java.ClassPresentationUtil; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.SearchScope; @@ -54,6 +56,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.MouseEvent; +import java.text.MessageFormat; import java.util.Arrays; import java.util.Comparator; @@ -119,6 +122,24 @@ public class MarkerType { navigateToOverridingMethod(e, method, method != element.getParent()); } }); + static final MarkerType SIBLING_OVERRIDING_METHOD = new MarkerType("SIBLING_OVERRIDING_METHOD", new NullableFunction() { + @Override + public String fun(PsiElement element) { + PsiElement parent = getParentMethod(element); + if (!(parent instanceof PsiMethod)) return null; + PsiMethod method = (PsiMethod)parent; + + return calculateOverridingSiblingMethodTooltip(method); + } + }, new LineMarkerNavigator() { + @Override + public void browse(MouseEvent e, PsiElement element) { + PsiElement parent = getParentMethod(element); + if (!(parent instanceof PsiMethod)) return; + PsiMethod method = (PsiMethod)parent; + navigateToSiblingOverridingMethod(e, method); + } + }); @Nullable private static String calculateOverridingMethodTooltip(@NotNull PsiMethod method, boolean acceptSelf) { @@ -139,6 +160,22 @@ public class MarkerType { } return composeText(superMethods, "", DaemonBundle.message(key), IdeActions.ACTION_GOTO_SUPER); } + @Nullable + private static String calculateOverridingSiblingMethodTooltip(@NotNull PsiMethod method) { + Pair pair = + FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, FindSuperElementsHelper.createSubClassCache()); + if (pair == null) return null; + PsiMethod superMethod = pair.getFirst(); + PsiClass subClass = pair.getSecond(); + boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); + boolean isSuperAbstract = superMethod.hasModifierProperty(PsiModifier.ABSTRACT); + + String postfix = MessageFormat.format(" via sub-class {0}", ClassPresentationUtil.getNameForClass(subClass, false)); + @NonNls String pattern = DaemonBundle.message(isSuperAbstract && !isAbstract ? + "method.implements" : + "method.overrides") + postfix; + return composeText(new PsiElement[]{superMethod}, "", pattern, IdeActions.ACTION_GOTO_SUPER); + } @NotNull private static String composeText(@NotNull PsiElement[] methods, @NotNull String start, @NotNull String pattern, @NotNull String actionId) { @@ -159,6 +196,14 @@ public class MarkerType { DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()), new MethodCellRenderer(showMethodNames)); } + private static void navigateToSiblingOverridingMethod(MouseEvent e, @NotNull PsiMethod method) { + PsiMethod superMethod = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method); + if (superMethod == null) return; + PsiElementListNavigator.openTargets(e, new NavigatablePsiElement[]{superMethod}, + DaemonBundle.message("navigation.title.super.method", method.getName()), + DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()), + new MethodCellRenderer(false)); + } @NotNull private static PsiMethod[] composeSuperMethods(@NotNull PsiMethod method, boolean acceptSelf) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java index 5fc8d7b07da2..f39d316b5bd1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java @@ -96,7 +96,7 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase { assertSame(MarkerType.OVERRIDDEN_METHOD.getNavigationHandler(), iMarker.getNavigationHandler()); LineMarkerInfo aMarker = findMarkerWithElement(markers, aRun.getNameIdentifier()); - assertSame(MarkerType.OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler()); + assertSame(MarkerType.SIBLING_OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler()); } private static LineMarkerInfo findMarkerWithElement(List markers, PsiElement psiMethod) { From f4ff001c64cb7f3f4957c654d5e8162c73e5581c Mon Sep 17 00:00:00 2001 From: Konstantin Ulitin Date: Wed, 2 Sep 2015 15:03:00 +0300 Subject: [PATCH 24/27] use common code style settings from grandparent language --- .../psi/codeStyle/CommonCodeStyleSettingsManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java index b59f14a8a709..61d827693091 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettingsManager.java @@ -61,8 +61,9 @@ public class CommonCodeStyleSettingsManager implements JDOMExternalizable { public CommonCodeStyleSettings getCommonSettings(@Nullable Language lang) { Map commonSettingsMap = getCommonSettingsMap(); CommonCodeStyleSettings settings = commonSettingsMap.get(lang); - if (settings == null && lang != null) { - settings = commonSettingsMap.get(lang.getBaseLanguage()); + while (settings == null && lang != null) { + lang = lang.getBaseLanguage(); + settings = commonSettingsMap.get(lang); } if (settings != null) { return settings; From 90f723e35e4685c1c8c8fe71b6fa6a143ca137d3 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 2 Sep 2015 15:40:00 +0300 Subject: [PATCH 25/27] show a message if all class fields were filtered out --- .../ui/tree/render/ClassRenderer.java | 19 ++++++++++++------- .../src/messages/DebuggerBundle.properties | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java index af418f3053e8..b950a4b0a328 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java @@ -158,16 +158,21 @@ public class ClassRenderer extends NodeRendererImpl{ final ObjectReference objRef = (ObjectReference)value; final ReferenceType refType = objRef.referenceType(); // default ObjectReference processing - final List fields = refType.allFields(); - if (fields.size() > 0) { - for (final Field field : fields) { - if (!shouldDisplay(evaluationContext, objRef, field)) { - continue; + List fields = refType.allFields(); + if (!fields.isEmpty()) { + boolean empty = true; + for (Field field : fields) { + if (shouldDisplay(evaluationContext, objRef, field)) { + children.add(nodeManager.createNode( + createFieldDescriptor(parentDescriptor, nodeDescriptorFactory, objRef, field, evaluationContext), evaluationContext)); + empty = false; } - children.add(nodeManager.createNode(createFieldDescriptor(parentDescriptor, nodeDescriptorFactory, objRef, field, evaluationContext), evaluationContext)); } - if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) { + if (empty) { + children.add(nodeManager.createMessageNode(DebuggerBundle.message("message.node.class.no.fields.to.display"))); + } + else if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isSortValues()) { Collections.sort(children, NodeManagerImpl.getNodeComparator()); } } diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 4e8f16a937b5..5cb85518e745 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -393,6 +393,7 @@ message.node.all.array.elements.null=All elements in range ({0}, {1}) are null message.node.all.elements.null=All elements are null message.node.empty.array=Empty message.node.class.has.no.fields=Class has no fields +message.node.class.no.fields.to.display=No fields to display message.node.object.collected=Object has been garbage collected during method invocation message.node.thread.running=Thread is running message.node.thread.has.no.frames=Thread has no frames From 10d5db3598532ebdc42d056b4c7e57c7560ef4de Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 2 Sep 2015 14:50:47 +0200 Subject: [PATCH 26/27] IDEA-144665 (Incorrect 'tearDown() is not called from finally block' inspection) --- .../SuperTearDownInFinallyInspection.java | 2 +- .../SuperTearDownInFinally.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/SuperTearDownInFinallyInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/SuperTearDownInFinallyInspection.java index 8bfce245a778..667c1592020c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/SuperTearDownInFinallyInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/SuperTearDownInFinallyInspection.java @@ -55,7 +55,7 @@ public class SuperTearDownInFinallyInspection extends BaseInspection { return; } final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiMember.class, PsiLambdaExpression.class); - if (method == null) { + if (method == null || !method.getName().equals("tearDown")) { return; } final PsiClass containingClass = method.getContainingClass(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/super_tear_down_in_finally/SuperTearDownInFinally.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/super_tear_down_in_finally/SuperTearDownInFinally.java index 869536184627..0cd7f1f9e1cf 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/super_tear_down_in_finally/SuperTearDownInFinally.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/super_tear_down_in_finally/SuperTearDownInFinally.java @@ -1,17 +1,19 @@ -class SuperTearDownInFinally extends junit.framework.TestCase { +import junit.framework.TestCase; + +class SuperTearDownInFinally extends TestCase { public void tearDown() throws Exception { super.tearDown(); System.out.println(); } } -class NoProblem extends junit.framework.TestCase { +class NoProblem extends TestCase { public void tearDown() throws Exception { super.tearDown(); } } -class CalledInFinally extends junit.framework.TestCase { +class CalledInFinally extends TestCase { public void tearDown() throws Exception { try { @@ -20,4 +22,16 @@ class CalledInFinally extends junit.framework.TestCase { super.tearDown(); } } +} +class SomeTest extends TestCase { + @Override + protected void setUp() throws Exception { + try { + super.setUp(); + } + catch (Throwable t) { + super.tearDown(); // yellow code + } + } + public void test_something() {} } \ No newline at end of file From c7821bd602662706781cff306feb3f24ae871689 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Wed, 2 Sep 2015 15:51:37 +0300 Subject: [PATCH 27/27] IDEA-144550 Garbled text in UI designer --- .../src/com/intellij/uiDesigner/designSurface/Painter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/Painter.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/Painter.java index c2f734e4748d..b0e7b77fa347 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/Painter.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/Painter.java @@ -15,6 +15,8 @@ */ package com.intellij.uiDesigner.designSurface; +import com.intellij.ide.ui.UISettings; +import com.intellij.ui.JBColor; import com.intellij.ui.LightColors; import com.intellij.uiDesigner.FormEditingUtil; import com.intellij.uiDesigner.SwingProperties; @@ -457,7 +459,8 @@ public final class Painter { Graphics2D g2d = (Graphics2D)g; g2d.setColor(PlatformColors.BLUE); g2d.fillRect(0, 0, (int)stringBounds.getWidth(), (int)stringBounds.getHeight()); - g2d.setColor(Color.WHITE); + g2d.setColor(JBColor.WHITE); + UISettings.setupAntialiasing(g); g.drawString(tagBuilder.toString(), 0, g.getFontMetrics().getAscent()); } }