From cc5281e6e32c5a714895c22e0d142fe00ca5ee4c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 30 Sep 2015 17:29:38 +0200 Subject: [PATCH 1/9] SSR: when replacing pattern method without body, copy body from matched element (part of IDEA-88738) --- .../structuralsearch/JavaReplaceHandler.java | 36 ++++++++++++------- .../StructuralReplaceTest.java | 15 ++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java index c94d67efe344..fd8be70e6759 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java @@ -127,18 +127,18 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { return getSymbolReplacementTarget(el) != null; } - @SuppressWarnings({"ConstantConditions"}) - private void handleModifierList(final PsiElement el, final PsiElement replacement) throws IncorrectOperationException { - // We want to copy all comments, including doc comments and modifier lists + @SuppressWarnings("ConstantConditions") + private void copyUnmatchedElements(final PsiElement original, final PsiElement replacement) { + // We want to copy all comments, including doc comments, modifier lists and method bodies // that are present in matched nodes but not present in search/replace Map newNameToSearchPatternNameMap = myContext.getNewName2PatternNameMap(); - Map originalNamedElements = Collector.collectNamedElements(el); + Map originalNamedElements = Collector.collectNamedElements(original); Map replacedNamedElements = Collector.collectNamedElements(replacement); if (originalNamedElements.size() == 0 && replacedNamedElements.size() == 0) { - Replacer.handleComments(el, replacement, myContext); + Replacer.handleComments(original, replacement, myContext); return; } @@ -149,7 +149,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { PsiNamedElement replacementNamedElement = replacedNamedElements.get(name); String key = newNameToSearchPatternNameMap.get(name); if (key == null) key = name; - PsiNamedElement searchNamedElement = searchedNamedElements.get(key); + PsiNamedElement searchedNamedElement = searchedNamedElements.get(key); if (replacementNamedElement == null && originalNamedElements.size() == 1 && replacedNamedElements.size() == 1) { replacementNamedElement = replacedNamedElements.entrySet().iterator().next().getValue(); @@ -170,7 +170,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } } - if (replacementNamedElement != null && searchNamedElement != null) { + if (replacementNamedElement != null && searchedNamedElement != null) { Replacer.handleComments(originalNamedElement, replacementNamedElement, myContext); } @@ -191,8 +191,8 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { ) { PsiModifierList modifierList = ((PsiModifierListOwner)originalNamedElements.get(name)).getModifierList(); - if (searchNamedElement instanceof PsiModifierListOwner) { - PsiModifierList modifierListOfSearchedElement = ((PsiModifierListOwner)searchNamedElement).getModifierList(); + if (searchedNamedElement instanceof PsiModifierListOwner) { + PsiModifierList modifierListOfSearchedElement = ((PsiModifierListOwner)searchedNamedElement).getModifierList(); final PsiModifierListOwner modifierListOwner = ((PsiModifierListOwner)replacementNamedElement); PsiModifierList modifierListOfReplacement = modifierListOwner.getModifierList(); @@ -215,6 +215,18 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } } } + + if (originalNamedElement instanceof PsiMethod && + searchedNamedElement instanceof PsiMethod && + replacementNamedElement instanceof PsiMethod) { + final PsiMethod searchedMethod = (PsiMethod)searchedNamedElement; + final PsiMethod replacementMethod = (PsiMethod)replacementNamedElement; + if (searchedMethod.getBody() == null && replacementMethod.getBody() == null) { + final PsiMethod originalMethod = (PsiMethod)originalNamedElement; + final PsiCodeBlock originalBody = originalMethod.getBody(); + replacementMethod.add(originalBody); + } + } } } @@ -267,12 +279,12 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { if (listContext) { if (statements.length > 1) { final PsiElement replacement = elementParent.addRangeBefore(statements[0], statements[statements.length - 1], elementToReplace); - handleModifierList(elementToReplace, replacement); + copyUnmatchedElements(elementToReplace, replacement); } else if (statements.length == 1) { PsiElement replacement = getMatchExpr(statements[0], elementToReplace); - handleModifierList(elementToReplace, replacement); + copyUnmatchedElements(elementToReplace, replacement); replacement = handleSymbolReplacement(replacement, elementToReplace); if (replacement instanceof PsiTryStatement) { @@ -337,7 +349,7 @@ public class JavaReplaceHandler extends StructuralReplaceHandler { } else { // preserve comments - handleModifierList(elementToReplace, replacement); + copyUnmatchedElements(elementToReplace, replacement); if (replacement instanceof PsiClass) { final PsiStatement[] searchStatements = getCodeBlock().getStatements(); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java index d00a252e400c..ffb67bb2bda3 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java @@ -2389,4 +2389,19 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase { options.clearVariableDefinitions(); } + + public void testMethodContentReplacement() { + final String in = "class A extends TestCase {\n" + + " void testOne() {\n" + + " System.out.println();\n" + + " }\n" + + "}\n"; + final String what = "class '_A { void '_b:[regex( test.* )](); }"; + final String by = "class $A$ {\n @java.lang.Override void $b$();\n}"; + assertEquals("class A extends TestCase {\n" + + " @Override void testOne(){\n" + + " System.out.println();\n" + + " }\n" + + "}\n", replacer.testReplace(in, what, by, options)); + } } \ No newline at end of file From 6897aa2b8bba6589fbc0cfebfa008bef7548af07 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 30 Sep 2015 19:44:51 +0300 Subject: [PATCH 2/9] fixed null suspend context for a thread when corresponding suspend context is evaluating --- .../com/intellij/debugger/engine/SuspendManagerUtil.java | 4 ++-- .../engine/events/DebuggerContextCommandImpl.java | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java index 17122aeb9ca8..cade42583013 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/SuspendManagerUtil.java @@ -18,10 +18,10 @@ package com.intellij.debugger.engine; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.containers.SmartHashSet; +import com.sun.jdi.request.EventRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashSet; import java.util.Set; public class SuspendManagerUtil { @@ -38,7 +38,7 @@ public class SuspendManagerUtil { public static SuspendContextImpl findContextByThread(SuspendManager suspendManager, ThreadReferenceProxyImpl thread) { for (SuspendContextImpl context : ((SuspendManagerImpl)suspendManager).getPausedContexts()) { - if (context.getThread() == thread) { + if (context.getThread() == thread || context.getSuspendPolicy() == EventRequest.SUSPEND_ALL) { return context; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java index c586f26a152f..f8bb99ba1af9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java @@ -41,15 +41,6 @@ public abstract class DebuggerContextCommandImpl extends SuspendContextCommandIm myCustomThread = customThread; } - @Nullable - @Override - public SuspendContextImpl getSuspendContext() { - if (myCustomThread != null) { - return SuspendManagerUtil.getSuspendingContext(myDebuggerContext.getDebugProcess().getSuspendManager(), myCustomThread); - } - return super.getSuspendContext(); - } - private ThreadReferenceProxyImpl getThread() { return myCustomThread != null ? myCustomThread : myDebuggerContext.getThreadProxy(); } From 962d8e66274a1445b070a8af07e4bdaaed0f63e0 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Wed, 30 Sep 2015 18:59:40 +0300 Subject: [PATCH 3/9] Do not log PCE in forUseInNonAWTThread-mode document --- .../intellij/openapi/editor/impl/DocumentImpl.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index dbe7cf828cf0..0eac672419d6 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -28,6 +28,7 @@ import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.editor.ex.*; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; @@ -118,6 +119,11 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { this(chars, false); } + /** + * NOTE: if client sets forUseInNonAWTThread to true it's supposed that client will completely control document and its listeners. + * The noticable peculiarity of DocumentImpl behavior in this mode is that DocumentImpl will survive after ProcessCancelledException + * thrown from listeners during changedUpdate event, the exception will be rethrown and rest of the listeners WON'T be notified. + */ public DocumentImpl(@NotNull CharSequence chars, boolean forUseInNonAWTThread) { this(chars, false, forUseInNonAWTThread); } @@ -756,6 +762,14 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { try { listener.documentChanged(event); } + catch (ProcessCanceledException e) { + if (!myAssertThreading) { + throw e; + } + else { + LOG.error("ProceeCanceledException shouldn't be thrown from document listeners on real document"); + } + } catch (Throwable e) { LOG.error(e); } From 455ac5d0051cb01220982925b6b5b2b35f7b591f Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 30 Sep 2015 21:01:41 +0300 Subject: [PATCH 4/9] fixed null suspend context for a thread when corresponding suspend context is evaluating - needs suspend context for SuspendContextCommandImpl processing --- .../engine/events/DebuggerContextCommandImpl.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java index f8bb99ba1af9..81096ecbcf86 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/events/DebuggerContextCommandImpl.java @@ -41,6 +41,15 @@ public abstract class DebuggerContextCommandImpl extends SuspendContextCommandIm myCustomThread = customThread; } + @Nullable + @Override + public SuspendContextImpl getSuspendContext() { + if (myCustomThread != null) { + return SuspendManagerUtil.findContextByThread(myDebuggerContext.getDebugProcess().getSuspendManager(), getThread()); + } + return super.getSuspendContext(); + } + private ThreadReferenceProxyImpl getThread() { return myCustomThread != null ? myCustomThread : myDebuggerContext.getThreadProxy(); } From 7d97620a9db00b359bc57626a7e50ee739fe10e5 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 30 Sep 2015 19:40:33 +0200 Subject: [PATCH 5/9] java scratches run support rewritten to dedicated configuration type --- .../application/ApplicationConfiguration.java | 13 +- .../ApplicationConfigurationProducer.java | 46 ++--- .../JavaScratchRunConfigurationExtension.java | 174 ------------------ .../JavaScratchCompilationSupport.java | 46 +++-- .../scratch/JavaScratchConfigurable.java | 107 +++++++++++ .../scratch/JavaScratchConfiguration.java | 132 +++++++++++++ .../JavaScratchConfigurationProducer.java | 82 +++++++++ .../scratch/JavaScratchConfigurationType.java | 89 +++++++++ .../JavaScratchPositionManager.java | 2 +- .../GroovyScriptRunConfigurationProducer.java | 3 +- resources/src/META-INF/IdeaPlugin.xml | 5 +- 11 files changed, 476 insertions(+), 223 deletions(-) delete mode 100644 java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java rename java/execution/impl/src/com/intellij/execution/{impl => scratch}/JavaScratchCompilationSupport.java (83%) create mode 100644 java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java create mode 100644 java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfiguration.java create mode 100644 java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationProducer.java create mode 100644 java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationType.java rename java/execution/impl/src/com/intellij/execution/{impl => scratch}/JavaScratchPositionManager.java (98%) diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java index a6eb2a1669e5..594c0b0fecbd 100644 --- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java +++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java @@ -259,12 +259,15 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration { +public class ApplicationConfigurationProducer extends JavaRunConfigurationProducerBase { - public ApplicationConfigurationProducer() { - super(ApplicationConfigurationType.getInstance()); + public ApplicationConfigurationProducer(final ApplicationConfigurationType configurationType) { + super(configurationType); } @Override - protected boolean setupConfigurationFromContext(ApplicationConfiguration configuration, - ConfigurationContext context, - Ref sourceElement) { - Location location = JavaExecutionUtil.stepIntoSingleClass(context.getLocation()); - if (location == null) return false; + protected boolean setupConfigurationFromContext(T configuration, ConfigurationContext context, Ref sourceElement) { + final Location contextLocation = context.getLocation(); + if (contextLocation == null) { + return false; + } + final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation); + if (location == null) { + return false; + } final PsiElement element = location.getPsiElement(); - if (!element.isPhysical()) return false; + if (!element.isPhysical()) { + return false; + } PsiElement currentElement = element; PsiMethod method; while ((method = findMain(currentElement)) != null) { @@ -60,15 +63,15 @@ public class ApplicationConfigurationProducer extends JavaRunConfigurationProduc currentElement = method.getParent(); } final PsiClass aClass = ApplicationConfigurationType.getMainClass(element); - if (aClass == null) return false; + if (aClass == null) { + return false; + } sourceElement.set(aClass); setupConfiguration(configuration, aClass, context); return true; } - private void setupConfiguration(ApplicationConfiguration configuration, - final PsiClass aClass, - final ConfigurationContext context) { + private void setupConfiguration(T configuration, final PsiClass aClass, final ConfigurationContext context) { configuration.MAIN_CLASS_NAME = JavaExecutionUtil.getRuntimeQualifiedName(aClass); configuration.setGeneratedName(); setupConfigurationModule(context, configuration); @@ -85,7 +88,7 @@ public class ApplicationConfigurationProducer extends JavaRunConfigurationProduc } @Override - public boolean isConfigurationFromContext(ApplicationConfiguration appConfiguration, ConfigurationContext context) { + public boolean isConfigurationFromContext(T appConfiguration, ConfigurationContext context) { final PsiElement location = context.getPsiLocation(); final PsiClass aClass = ApplicationConfigurationType.getMainClass(location); if (aClass != null && Comparing.equal(JavaExecutionUtil.getRuntimeQualifiedName(aClass), appConfiguration.MAIN_CLASS_NAME)) { @@ -94,15 +97,6 @@ public class ApplicationConfigurationProducer extends JavaRunConfigurationProduc return false; } - // for scratches it is enough to check that the configuration is associated with the same scratch file - final VirtualFile scratchFile = JavaScratchRunConfigurationExtension.getScratchVirtualFile(appConfiguration); - if (scratchFile != null) { - final PsiFile containingFile = aClass.getContainingFile(); - if (containingFile != null && scratchFile.equals(containingFile.getVirtualFile())) { - return true; - } - } - final Module configurationModule = appConfiguration.getConfigurationModule().getModule(); if (Comparing.equal(context.getModule(), configurationModule)) return true; diff --git a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java b/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java deleted file mode 100644 index cfc93d3f0316..000000000000 --- a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchRunConfigurationExtension.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.execution.impl; - -import com.intellij.debugger.DebuggerManager; -import com.intellij.debugger.engine.DebugProcess; -import com.intellij.debugger.engine.DebugProcessAdapter; -import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.Location; -import com.intellij.execution.RunConfigurationExtension; -import com.intellij.execution.application.ApplicationConfiguration; -import com.intellij.execution.configurations.*; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.ide.scratch.ScratchFileType; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.compiler.CompilerManager; -import com.intellij.openapi.options.SettingsEditor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileWithId; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.psi.PsiFile; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; - -public class JavaScratchRunConfigurationExtension extends RunConfigurationExtension{ - - private static final Key SCRATCH_FILE_ID = Key.create("_scratch_file_id_"); - - public void cleanUserData(RunConfigurationBase configuration) { - super.cleanUserData(configuration); - configuration.putCopyableUserData(SCRATCH_FILE_ID, null); - } - - protected void extendCreatedConfiguration(@NotNull RunConfigurationBase configuration, @NotNull Location location) { - final VirtualFile vFile = location.getVirtualFile(); - if (vFile instanceof VirtualFileWithId && vFile.getFileType() == ScratchFileType.INSTANCE) { - final PsiFile psiFile = location.getPsiElement().getContainingFile(); - if (psiFile != null && psiFile.getLanguage() == JavaLanguage.INSTANCE) { - configuration.putCopyableUserData(SCRATCH_FILE_ID, ((VirtualFileWithId)vFile).getId()); - } - } - } - - protected void validateConfiguration(@NotNull RunConfigurationBase configuration, boolean isExecution) throws Exception { - super.validateConfiguration(configuration, isExecution); - } - - public void updateJavaParameters(T configuration, JavaParameters params, RunnerSettings runnerSettings) throws ExecutionException { - if (getScratchFileId(configuration) >= 0) { - final File scrachesOutput = getScratchOutputDirectory(configuration.getProject()); - if (scrachesOutput != null) { - params.getClassPath().add(scrachesOutput); - } - } - } - - @Override - protected void attachToProcess(@NotNull final RunConfigurationBase configuration, @NotNull final ProcessHandler handler, @Nullable RunnerSettings runnerSettings) { - if (runnerSettings instanceof DebuggingRunnerData && getScratchFileId(configuration) >= 0) { - final VirtualFile vFile = getScratchVirtualFile(configuration); - if (vFile != null) { - DebuggerManager.getInstance(configuration.getProject()).addDebugProcessListener(handler, new DebugProcessAdapter() { - @Override - public void processAttached(DebugProcess process) { - if (vFile.isValid()) { - process.appendPositionManager(new JavaScratchPositionManager((DebugProcessImpl)process, vFile)); - } - process.removeDebugProcessListener(this); - } - }); - } - } - } - - @NotNull - protected String getSerializationId() { - return "java-scratch-properties"; - } - - @Nullable - public static String getScratchFileUrl(RunConfiguration configuration) { - final VirtualFile vFile = getScratchVirtualFile(configuration); - return vFile != null? vFile.getUrl() : null; - } - - @Nullable - public static VirtualFile getScratchVirtualFile(RunConfiguration configuration) { - int id = getScratchFileId(configuration); - if (id < 0) { - return null; - } - return ManagingFS.getInstance().findFileById(id); - } - - private static int getScratchFileId(RunConfiguration configuration) { - final Integer id = - configuration instanceof RunConfigurationBase ? ((RunConfigurationBase)configuration).getCopyableUserData(SCRATCH_FILE_ID) : null; - return id == null? -1 : id.intValue(); - } - - @Nullable - public static File getScratchOutputDirectory(Project project) { - final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir(); - return root != null? new File(root, "scratches/out") : null; - } - - @Nullable - public static File getScratchTempDirectory(Project project) { - final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir(); - return root != null? new File(root, "scratches/src") : null; - } - - - protected void readExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws InvalidDataException { - final Element sourceElement = element.getChild("source"); - if (sourceElement != null) { - final String idStr = sourceElement.getAttributeValue("fileId"); - if (idStr != null) { - try { - runConfiguration.putCopyableUserData(SCRATCH_FILE_ID, Integer.parseInt(idStr)); - } - catch (NumberFormatException ignored) { - } - } - } - } - - protected void writeExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws WriteExternalException { - final int id = getScratchFileId(runConfiguration); - if (id < 0) { - super.writeExternal(runConfiguration, element); - } - else { - final Element sourceElement = new Element("source"); - sourceElement.setAttribute("fileId", String.valueOf(id)); - element.addContent(sourceElement); - } - } - - @Nullable - protected

SettingsEditor

createEditor(@NotNull P configuration) { - return null; - } - - @Nullable - protected String getEditorTitle() { - return null; - } - - protected boolean isApplicableFor(@NotNull RunConfigurationBase configuration) { - return configuration instanceof ApplicationConfiguration; - } -} diff --git a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchCompilationSupport.java similarity index 83% rename from java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java rename to java/execution/impl/src/com/intellij/execution/scratch/JavaScratchCompilationSupport.java index 1f8d401b6693..26be9ec53d5f 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchCompilationSupport.java +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchCompilationSupport.java @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.execution.impl; +package com.intellij.execution.scratch; import com.intellij.compiler.options.CompileStepBeforeRun; -import com.intellij.execution.configurations.ModuleBasedConfiguration; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.*; @@ -53,20 +52,34 @@ public class JavaScratchCompilationSupport implements ProjectComponent, CompileT compileManager.addAfterTask(this); } + @Nullable + public static File getScratchOutputDirectory(Project project) { + final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir(); + return root != null? new File(root, "scratches/out") : null; + } + + @Nullable + public static File getScratchTempDirectory(Project project) { + final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir(); + return root != null? new File(root, "scratches/src") : null; + } + @Override public boolean execute(CompileContext context) { final Project project = context.getProject(); final RunConfiguration configuration = CompileStepBeforeRun.getRunConfiguration(context); - if (!(configuration instanceof ModuleBasedConfiguration)) { + if (!(configuration instanceof JavaScratchConfiguration)) { return true; } - final String scratchUrl = JavaScratchRunConfigurationExtension.getScratchFileUrl(configuration); + final JavaScratchConfiguration scratchConfig = (JavaScratchConfiguration)configuration; + final String scratchUrl = scratchConfig.getScratchFileUrl(); if (scratchUrl == null) { - return true; + context.addMessage(CompilerMessageCategory.ERROR, "Associated scratch file not found", null, -1, -1); + return false; } @Nullable - final Module module = ((ModuleBasedConfiguration)configuration).getConfigurationModule().getModule(); + final Module module = scratchConfig.getConfigurationModule().getModule(); final Sdk targetSdk = module != null? ModuleRootManager.getInstance(module).getSdk() : ProjectRootManager.getInstance(project).getProjectSdk(); if (targetSdk == null) { final String message = module != null? @@ -83,7 +96,7 @@ public class JavaScratchCompilationSupport implements ProjectComponent, CompileT return true; } - final File outputDir = JavaScratchRunConfigurationExtension.getScratchOutputDirectory(project); + final File outputDir = getScratchOutputDirectory(project); if (outputDir == null) { // should not happen for normal projects return true; } @@ -94,7 +107,7 @@ public class JavaScratchCompilationSupport implements ProjectComponent, CompileT File srcFile = scratchFile; if (!StringUtil.endsWith(srcFile.getName(), ".java")) { - final File srcDir = JavaScratchRunConfigurationExtension.getScratchTempDirectory(project); + final File srcDir = getScratchTempDirectory(project); if (srcDir == null) { // should not happen for normal projects return true; } @@ -150,12 +163,17 @@ public class JavaScratchCompilationSupport implements ProjectComponent, CompileT } }; - for (String s : orderEnumerator.compute().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList().getPathList()) { - cp.add(new File(s)); - } - for (String s : orderEnumerator.compute().compileOnly().sdkOnly().getPathsList().getPathList()) { - platformCp.add(new File(s)); - } + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + for (String s : orderEnumerator.compute().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList().getPathList()) { + cp.add(new File(s)); + } + for (String s : orderEnumerator.compute().compileOnly().sdkOnly().getPathsList().getPathList()) { + platformCp.add(new File(s)); + } + } + }); final List options = new ArrayList(); options.add("-g"); // always compile with debug info diff --git a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java new file mode 100644 index 000000000000..ea2eaca3da5c --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurable.java @@ -0,0 +1,107 @@ +/* + * 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.execution.scratch; + +import com.intellij.execution.application.ApplicationConfigurable; +import com.intellij.execution.application.ApplicationConfiguration; +import com.intellij.ide.scratch.ScratchFileService; +import com.intellij.ide.scratch.ScratchRootType; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.ui.components.BorderLayoutPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * @author Eugene Zhuravlev + * Date: 30-Sep-15 + */ +public class JavaScratchConfigurable extends ApplicationConfigurable{ + + private final TextFieldWithBrowseButton myScratchPathField; + + public JavaScratchConfigurable(final Project project) { + super(project); + myScratchPathField = new TextFieldWithBrowseButton(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + VirtualFile toSelect = getVFileFromEditor(); + if (toSelect == null) { + final String scratchesRoot = ScratchFileService.getInstance().getRootPath(ScratchRootType.getInstance()); + toSelect = LocalFileSystem.getInstance().findFileByPath(scratchesRoot); + } + final VirtualFile file = + FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(), myScratchPathField, project, toSelect); + if (file != null) { + setVFileToEditor(file); + } + } + }, this); + } + + @Override + public void applyEditorTo(ApplicationConfiguration configuration) throws ConfigurationException { + super.applyEditorTo(configuration); + final VirtualFile vFile = getVFileFromEditor(); + ((JavaScratchConfiguration)configuration).SCRATCH_FILE_ID = vFile instanceof VirtualFileWithId ? ((VirtualFileWithId)vFile).getId() : 0; + } + + @Nullable + private VirtualFile getVFileFromEditor() { + final String path = FileUtil.toSystemIndependentName(myScratchPathField.getText()); + return !StringUtil.isEmpty(path) ? LocalFileSystem.getInstance().findFileByPath(path) : null; + } + + @Override + public void resetEditorFrom(ApplicationConfiguration configuration) { + super.resetEditorFrom(configuration); + final JavaScratchConfiguration scratchConfig = (JavaScratchConfiguration)configuration; + final VirtualFile file = scratchConfig.getScratchVirtualFile(); + setVFileToEditor(file); + } + + private void setVFileToEditor(VirtualFile file) { + if (file != null) { + myScratchPathField.setText(FileUtil.toSystemDependentName(file.getPath())); + } + else { + myScratchPathField.setText(""); + } + } + + @NotNull + @Override + public JComponent createEditor() { + final JPanel panel = new JPanel(new GridBagLayout()); + panel.add(new JBLabel("Path to scratch file: "), new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(20,0,0,10), 0, 0)); + panel.add(myScratchPathField, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(20, 0, 0, 0), 0, 0)); + return new BorderLayoutPanel().addToCenter(super.createEditor()).addToBottom(panel); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfiguration.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfiguration.java new file mode 100644 index 000000000000..b3f2f7e827c3 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfiguration.java @@ -0,0 +1,132 @@ +/* + * 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.execution.scratch; + +import com.intellij.debugger.DebuggerManager; +import com.intellij.debugger.engine.DebugProcess; +import com.intellij.debugger.engine.DebugProcessAdapter; +import com.intellij.debugger.engine.DebugProcessImpl; +import com.intellij.execution.ExecutionBundle; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.JavaRunConfigurationExtensionManager; +import com.intellij.execution.application.ApplicationConfiguration; +import com.intellij.execution.configurations.*; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.util.JavaParametersUtil; +import com.intellij.execution.util.ProgramParametersUtil; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.ManagingFS; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + +/** + * @author Eugene Zhuravlev + * Date: 29-Sep-15 + */ +public class JavaScratchConfiguration extends ApplicationConfiguration { + public int SCRATCH_FILE_ID; + + protected JavaScratchConfiguration(String name, Project project, ConfigurationFactory factory) { + super(name, project, factory); + } + + @Override + public void checkConfiguration() throws RuntimeConfigurationException { + JavaParametersUtil.checkAlternativeJRE(this); + final String className = MAIN_CLASS_NAME; + if (className == null || className.length() == 0) { + throw new RuntimeConfigurationError(ExecutionBundle.message("no.main.class.specified.error.text")); + } + if (SCRATCH_FILE_ID <= 0) { + throw new RuntimeConfigurationError("No scratch file associated with configuration"); + } + if (getScratchVirtualFile() == null) { + throw new RuntimeConfigurationError("Associated scratch file not found"); + } + ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), getConfigurationModule().getModule()); + JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this); + } + + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException { + final JavaCommandLineState state = new JavaApplicationCommandLineState(this, env) { + @Override + protected void setupJavaParameters(JavaParameters params) throws ExecutionException { + super.setupJavaParameters(params); + final File scrachesOutput = JavaScratchCompilationSupport.getScratchOutputDirectory(getProject()); + if (scrachesOutput != null) { + params.getClassPath().add(scrachesOutput); + } + } + + @NotNull + @Override + protected OSProcessHandler startProcess() throws ExecutionException { + final OSProcessHandler handler = super.startProcess(); + if (getRunnerSettings() instanceof DebuggingRunnerData) { + final VirtualFile vFile = getConfiguration().getScratchVirtualFile(); + if (vFile != null) { + DebuggerManager.getInstance(getProject()).addDebugProcessListener(handler, new DebugProcessAdapter() { + @Override + public void processAttached(DebugProcess process) { + if (vFile.isValid()) { + process.appendPositionManager(new JavaScratchPositionManager((DebugProcessImpl)process, vFile)); + } + process.removeDebugProcessListener(this); + } + }); + } + } + return handler; + } + }; + state.setConsoleBuilder(TextConsoleBuilderFactory.getInstance().createBuilder(getProject(), getConfigurationModule().getSearchScope())); + return state; + } + + @NotNull + @Override + public SettingsEditor getConfigurationEditor() { + return new JavaScratchConfigurable(getProject()); + } + + @Override + public boolean isCompileBeforeLaunchAddedByDefault() { + return true; + } + + @Nullable + public String getScratchFileUrl() { + final VirtualFile vFile = getScratchVirtualFile(); + return vFile != null? vFile.getUrl() : null; + } + + @Nullable + public VirtualFile getScratchVirtualFile() { + final int id = SCRATCH_FILE_ID; + if (id <= 0) { + return null; + } + return ManagingFS.getInstance().findFileById(id); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationProducer.java new file mode 100644 index 000000000000..6e716b31e13b --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationProducer.java @@ -0,0 +1,82 @@ +/* + * 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.execution.scratch; + +import com.intellij.execution.JavaExecutionUtil; +import com.intellij.execution.Location; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.ConfigurationFromContext; +import com.intellij.execution.application.ApplicationConfigurationProducer; +import com.intellij.execution.application.ApplicationConfigurationType; +import com.intellij.ide.scratch.ScratchFileType; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; + +/** + * @author Eugene Zhuravlev + * Date: 29-Sep-15 + */ +public class JavaScratchConfigurationProducer extends ApplicationConfigurationProducer { + + public JavaScratchConfigurationProducer() { + super(JavaScratchConfigurationType.getInstance()); + } + + @Override + protected boolean setupConfigurationFromContext(JavaScratchConfiguration configuration, ConfigurationContext context, Ref sourceElement) { + final Location location = context.getLocation(); + if (location != null) { + final VirtualFile vFile = location.getVirtualFile(); + if (vFile instanceof VirtualFileWithId && vFile.getFileType() == ScratchFileType.INSTANCE) { + final PsiFile psiFile = location.getPsiElement().getContainingFile(); + if (psiFile != null && psiFile.getLanguage() == JavaLanguage.INSTANCE) { + configuration.SCRATCH_FILE_ID = ((VirtualFileWithId)vFile).getId(); + return super.setupConfigurationFromContext(configuration, context, sourceElement); + } + } + } + return false; + } + + @Override + public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) { + return other.isProducedBy(ApplicationConfigurationProducer.class) && !other.isProducedBy(JavaScratchConfigurationProducer.class); + } + + @Override + public boolean isConfigurationFromContext(JavaScratchConfiguration configuration, ConfigurationContext context) { + final PsiElement location = context.getPsiLocation(); + final PsiClass aClass = ApplicationConfigurationType.getMainClass(location); + if (aClass != null && Comparing.equal(JavaExecutionUtil.getRuntimeQualifiedName(aClass), configuration.MAIN_CLASS_NAME)) { + // for scratches it is enough to check that the configuration is associated with the same scratch file + final VirtualFile scratchFile = configuration.getScratchVirtualFile(); + if (scratchFile != null) { + final PsiFile containingFile = aClass.getContainingFile(); + if (containingFile != null && scratchFile.equals(containingFile.getVirtualFile())) { + return true; + } + } + } + return false; + } + +} diff --git a/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationType.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationType.java new file mode 100644 index 000000000000..4f6f67b0cd56 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchConfigurationType.java @@ -0,0 +1,89 @@ +/* + * 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.execution.scratch; + +import com.intellij.execution.application.ApplicationConfigurationType; +import com.intellij.execution.configuration.ConfigurationFactoryEx; +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.execution.configurations.ModuleBasedConfiguration; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.ui.LayeredIcon; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Eugene Zhuravlev + * Date: 29-Sep-15 + */ +public class JavaScratchConfigurationType extends ApplicationConfigurationType{ + private final ConfigurationFactory myFactory; + + public JavaScratchConfigurationType() { + myFactory = new ConfigurationFactoryEx(this) { + @Override + public boolean isApplicable(@NotNull Project project) { + return false; + } + + @NotNull + @Override + public RunConfiguration createTemplateConfiguration(@NotNull Project project) { + return new JavaScratchConfiguration("", project, this); + } + + @Override + public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) { + ((ModuleBasedConfiguration)configuration).onNewConfigurationCreated(); + } + }; + } + + @NotNull + @Override + public String getId() { + return "Java Scratch"; + } + + @Override + public String getDisplayName() { + return "Java Scratch"; + } + + @Override + public String getConfigurationTypeDescription() { + return "Configuration for java scratch files"; + } + + @Override + public Icon getIcon() { + return LayeredIcon.create(super.getIcon(), AllIcons.Actions.Scratch); // todo + } + + @Override + public ConfigurationFactory[] getConfigurationFactories() { + return new ConfigurationFactory[] {myFactory}; + } + + /** @noinspection MethodOverridesStaticMethodOfSuperclass*/ + @NotNull + public static JavaScratchConfigurationType getInstance() { + return ConfigurationTypeUtil.findConfigurationType(JavaScratchConfigurationType.class); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchPositionManager.java b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchPositionManager.java similarity index 98% rename from java/execution/impl/src/com/intellij/execution/impl/JavaScratchPositionManager.java rename to java/execution/impl/src/com/intellij/execution/scratch/JavaScratchPositionManager.java index 86318a45ddf9..46756fc35048 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/JavaScratchPositionManager.java +++ b/java/execution/impl/src/com/intellij/execution/scratch/JavaScratchPositionManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.execution.impl; +package com.intellij.execution.scratch; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.PositionManagerImpl; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java index f2f68b717e88..6fda6aea8d6f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java @@ -22,6 +22,7 @@ import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.execution.application.ApplicationConfigurationProducer; +import com.intellij.execution.application.ApplicationConfigurationType; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.configurations.RunConfigurationModule; import com.intellij.execution.junit.RuntimeConfigurationProducer; @@ -75,7 +76,7 @@ public class GroovyScriptRunConfigurationProducer extends RuntimeConfigurationPr } if (file.getText().contains("@Grab")) { - ApplicationConfigurationProducer producer = new ApplicationConfigurationProducer(); + ApplicationConfigurationProducer producer = new ApplicationConfigurationProducer(ApplicationConfigurationType.getInstance()); ConfigurationFromContext settings = producer.createConfigurationFromContext(context); if (settings != null) { PsiElement src = settings.getSourceElement(); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 7083ed3dea88..61721eea2f8d 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -68,7 +68,7 @@ - com.intellij.execution.impl.JavaScratchCompilationSupport + com.intellij.execution.scratch.JavaScratchCompilationSupport @@ -1326,8 +1326,10 @@ + + @@ -1619,7 +1621,6 @@ - From 7f2fe8c5a289a76ca67dd6866d9270be6398b653 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 30 Sep 2015 18:11:58 +0200 Subject: [PATCH 6/9] logging for EA-70518 - IAE: UsageInfoUsageAdapter. --- .../src/com/intellij/refactoring/BaseRefactoringProcessor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index 865026cd9a01..a22c14f226cd 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -216,6 +216,9 @@ public abstract class BaseRefactoringProcessor implements Runnable { } } if (isPreview) { + for (UsageInfo usage : usages) { + LOG.assertTrue(usage != null, getClass()); + } previewRefactoring(usages); } else { From 9dabc8ed14b5b76f2a87ef2c2c989c5ce66b7cee Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 30 Sep 2015 20:29:15 +0200 Subject: [PATCH 7/9] create from usage: fix target class when created from super expression (IDEA-145227) include all classes in tests in target and choose the first available --- .../impl/quickfix/CreateFromUsageBaseFix.java | 6 +-- .../quickfix/CreateMethodFromUsageFix.java | 5 ++- .../quickFix/CreateMethodFromUsageTest.groovy | 43 ++++++++++++++++++- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java index e7483d0a3532..5a9e3cbce898 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java @@ -94,7 +94,7 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { List targetClasses = getTargetClasses(element); if (targetClasses.isEmpty()) return; - if (targetClasses.size() == 1) { + if (targetClasses.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { doInvoke(project, targetClasses.get(0)); } else { chooseTargetClass(targetClasses, editor); @@ -379,10 +379,6 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { return Collections.emptyList(); } - if (ApplicationManager.getApplication().isUnitTestMode()) { - return Collections.singletonList(psiClass); - } - if (!allowOuterClasses || !isAllowOuterTargetClass()) { final ArrayList classes = new ArrayList(); collectSupers(psiClass, classes); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index ad3d3fc8010a..66a932d49661 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -120,7 +120,10 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { PsiMethodCallExpression call = getMethodCall(); if (call == null) return Collections.emptyList(); for (PsiClass target : targets) { - if (target.isInterface() && shouldCreateStaticMember(call.getMethodExpression(), target) && !PsiUtil.isLanguageLevel8OrHigher(target)) continue; + if (shouldCreateStaticMember(call.getMethodExpression(), target)){ + if (target.isInterface() && !PsiUtil.isLanguageLevel8OrHigher(target)) continue; + if (target.getContainingClass() != null && !target.hasModifierProperty(PsiModifier.STATIC)) continue; + } if (!isMethodSignatureExists(call, target)) { result.add(target); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateMethodFromUsageTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateMethodFromUsageTest.groovy index f879d01a768b..75ee4fb449bf 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateMethodFromUsageTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/CreateMethodFromUsageTest.groovy @@ -20,13 +20,11 @@ import com.intellij.ide.DataManager import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.actionSystem.EditorActionManager import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiMethod import com.intellij.psi.PsiModifier import com.intellij.psi.util.PsiTreeUtil - /** * @author ven */ @@ -132,6 +130,47 @@ class Usage { state.gotoEnd() } + public void "test prefer outer class when static is not applicable for inner"() { + configureFromFileText "a.java", """ +class A { + int x; + A(int x) { this.x = x; } + class B extends A{ + B(int x) { super(foo(x)); } + } +} +""" + TemplateManagerImpl.setTemplateTesting(project, testRootDisposable); + doAction("Create method 'foo'") + def state = TemplateManagerImpl.getTemplateState(getEditor()) + + def document = getEditor().getDocument() + def offset = getEditor().getCaretModel().getOffset() + + ApplicationManager.application.runWriteAction { + def method = PsiTreeUtil.getParentOfType(getFile().findElementAt(offset), PsiMethod.class) + method.getModifierList().setModifierProperty(PsiModifier.STATIC, false) + PsiDocumentManager.getInstance(getFile().project).commitDocument(document) + } + + state.gotoEnd() + + checkResultByText """ +class A { + int x; + A(int x) { this.x = x; } + class B extends A{ + B(int x) { super(foo(x)); } + } + + private int foo(int x) { + return 0; + } +} +""" + + } + @Override protected String getBasePath() { return "/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromUsage"; From 4187705448af8d553f1c949362b56374ef4bbabf Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 30 Sep 2015 21:55:03 +0300 Subject: [PATCH 8/9] skip NPE from CAccessible with new FQN too --- .../platform-impl/src/com/intellij/ide/SwingCleanuper.java | 4 ++++ .../src/com/intellij/ide/ToolkitBugsProcessor.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java b/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java index 2df05753b12f..bd5761bfabc7 100644 --- a/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java +++ b/platform/platform-impl/src/com/intellij/ide/SwingCleanuper.java @@ -237,6 +237,10 @@ public final class SwingCleanuper implements ApplicationComponent{ private static boolean isCAccessible(Object resource) { final String name = resource.getClass().getName(); + return isCAccessible(name); + } + + static boolean isCAccessible(String name) { return name.equals("apple.awt.CAccessible") || name.equals("sun.lwawt.macosx.CAccessible"); } diff --git a/platform/platform-impl/src/com/intellij/ide/ToolkitBugsProcessor.java b/platform/platform-impl/src/com/intellij/ide/ToolkitBugsProcessor.java index 58eb6998edab..798a15c6c630 100644 --- a/platform/platform-impl/src/com/intellij/ide/ToolkitBugsProcessor.java +++ b/platform/platform-impl/src/com/intellij/ide/ToolkitBugsProcessor.java @@ -188,7 +188,7 @@ public class ToolkitBugsProcessor { @Override public boolean process(Throwable e, StackTraceElement[] stack) { if (e instanceof NullPointerException && stack.length > 1) { - return stack[0].getClassName().equals("apple.awt.CAccessible") && stack[0].getMethodName().equals("getAccessibleContext"); + return SwingCleanuper.isCAccessible(stack[0].getClassName()) && stack[0].getMethodName().equals("getAccessibleContext"); } return false; } From 9f7d902044332ce0bd9760eabe9ba57c82c6d7c1 Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Wed, 30 Sep 2015 22:00:11 +0300 Subject: [PATCH 9/9] fix leak of combo box via action shortcut --- platform/lang-impl/src/com/intellij/find/impl/FindDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 81cd035a41c7..a8e9f0fdd7f3 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -360,7 +360,7 @@ public class FindDialog extends DialogWrapper { navigateToSelectedUsage(myResultsPreviewTable); } } - }.registerCustomShortcutSet(CommonShortcuts.getEditSource(), comboBox); + }.registerCustomShortcutSet(CommonShortcuts.getEditSource(), comboBox, myDisposable); } }