diff --git a/RegExpSupport/src/org/intellij/lang/regexp/inspection/RegExpEquivalenceChecker.java b/RegExpSupport/src/org/intellij/lang/regexp/inspection/RegExpEquivalenceChecker.java index 322acc674970..7b4dce246c7d 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/inspection/RegExpEquivalenceChecker.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/inspection/RegExpEquivalenceChecker.java @@ -180,7 +180,7 @@ class RegExpEquivalenceChecker { return true; } - public static boolean areBranchesEquivalent(RegExpBranch branch1, RegExpBranch branch2) { + private static boolean areBranchesEquivalent(RegExpBranch branch1, RegExpBranch branch2) { final RegExpAtom[] atoms1 = branch1.getAtoms(); final RegExpAtom[] atoms2 = branch2.getAtoms(); if (atoms1.length != atoms2.length) { @@ -194,7 +194,7 @@ class RegExpEquivalenceChecker { return true; } - public static boolean areCharsEquivalent(RegExpChar aChar1, RegExpChar aChar2) { + private static boolean areCharsEquivalent(RegExpChar aChar1, RegExpChar aChar2) { return aChar1.getValue() == aChar2.getValue(); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index f90ede5ddc2b..518656d0c463 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -178,6 +178,15 @@ public class JavaMethodCallElement extends LookupItem implements Type } PsiCallExpression methodCall = findCallAtOffset(context, context.getOffset(refStart)); + // make sure this is the method call we've just added, not the enclosing one + if (methodCall != null) { + PsiElement completedElement = methodCall instanceof PsiMethodCallExpression ? + ((PsiMethodCallExpression)methodCall).getMethodExpression().getReferenceNameElement() : null; + TextRange completedElementRange = completedElement == null ? null : completedElement.getTextRange(); + if (completedElementRange == null || completedElementRange.getStartOffset() != context.getStartOffset()) { + methodCall = null; + } + } if (methodCall != null) { CompletionMemory.registerChosenMethod(method, methodCall); handleNegation(context, document, method, methodCall); diff --git a/java/java-psi-impl/src/com/intellij/core/JavaCoreApplicationEnvironment.java b/java/java-psi-impl/src/com/intellij/core/JavaCoreApplicationEnvironment.java index 27cfe2779f70..a5682cfbdb6b 100644 --- a/java/java-psi-impl/src/com/intellij/core/JavaCoreApplicationEnvironment.java +++ b/java/java-psi-impl/src/com/intellij/core/JavaCoreApplicationEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,11 @@ import org.jetbrains.annotations.NotNull; @SuppressWarnings("UnusedDeclaration") // Upsource and Kotlin public class JavaCoreApplicationEnvironment extends CoreApplicationEnvironment { public JavaCoreApplicationEnvironment(@NotNull Disposable parentDisposable) { - super(parentDisposable); + this(parentDisposable, true); + } + + public JavaCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) { + super(parentDisposable, unitTestMode); registerFileType(JavaClassFileType.INSTANCE, "class"); registerFileType(JavaFileType.INSTANCE, "java"); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionHintsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionHintsTest.java index b0a417be6f0f..658cb634cc47 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionHintsTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/CompletionHintsTest.java @@ -106,6 +106,22 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase { myFixture.checkResult("class C { void m() { Character.toChars(123, , ) } }"); } + public void testNoHintsForMethodReference() { + myFixture.configureByText(JavaFileType.INSTANCE, "class C {\n" + + " interface I { void i(int p); }\n" + + " void referenced(int a) {}\n" + + " void m(I lambda) {}\n" + + " void m2() { m(this::) }\n" + + "}"); + complete("referenced"); + myFixture.checkResultWithInlays("class C {\n" + + " interface I { void i(int p); }\n" + + " void referenced(int a) {}\n" + + " void m(I lambda) {}\n" + + " void m2() { m(this::referenced) }\n" + + "}"); + } + private void showParameterInfo() { myFixture.performEditorAction("ParameterInfo"); UIUtil.dispatchAllInvocationEvents(); diff --git a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java index 9a0460ebe548..7b6944bf6ab1 100644 --- a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.impl.CoreCommandProcessor; import com.intellij.openapi.components.ExtensionAreas; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.ExtensionPointName; @@ -42,7 +41,6 @@ import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeExtension; -import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.impl.CoreProgressManager; @@ -67,7 +65,6 @@ import com.intellij.psi.meta.MetaDataRegistrar; import com.intellij.psi.stubs.CoreStubTreeLoader; import com.intellij.psi.stubs.StubTreeLoader; import com.intellij.util.Consumer; -import com.intellij.util.Function; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.picocontainer.MutablePicoContainer; @@ -87,9 +84,15 @@ public class CoreApplicationEnvironment { private final CoreLocalFileSystem myLocalFileSystem; protected final VirtualFileSystem myJarFileSystem; @NotNull private final Disposable myParentDisposable; + private final boolean myUnitTestMode; public CoreApplicationEnvironment(@NotNull Disposable parentDisposable) { + this(parentDisposable, true); + } + + public CoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) { myParentDisposable = parentDisposable; + myUnitTestMode = unitTestMode; myFileTypeRegistry = new CoreFileTypeRegistry(); @@ -138,7 +141,12 @@ public class CoreApplicationEnvironment { @NotNull protected MockApplication createApplication(@NotNull Disposable parentDisposable) { - return new MockApplicationEx(parentDisposable); + return new MockApplicationEx(parentDisposable) { + @Override + public boolean isUnitTestMode() { + return myUnitTestMode; + } + }; } @NotNull diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java index afc67e44b495..5766203dea0e 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java @@ -16,6 +16,8 @@ package com.intellij.psi.impl.smartPointers; import com.intellij.lang.LanguageUtil; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.ProperTextRange; import com.intellij.openapi.util.Segment; import com.intellij.openapi.util.TextRange; @@ -88,7 +90,7 @@ class AnchorElementInfo extends SelfElementInfo { return packed1 == packed2; } if (packed1 != -1 || packed2 != -1) { - return areRestoredElementsEqual(other); + return ReadAction.compute(() -> Comparing.equal(restoreElement(), other.restoreElement())); } } return super.pointsToTheSameElementAs(other); diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/DirElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/DirElementInfo.java index 393523c753d9..5dc75b10cb3d 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/DirElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/DirElementInfo.java @@ -55,10 +55,7 @@ class DirElementInfo extends SmartPointerElementInfo { @Override public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) { - if (other instanceof DirElementInfo) { - return Comparing.equal(myVirtualFile, ((DirElementInfo)other).myVirtualFile); - } - return Comparing.equal(restoreElement(), other.restoreElement()); + return other instanceof DirElementInfo && Comparing.equal(myVirtualFile, ((DirElementInfo)other).myVirtualFile); } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java index 804a803f5be7..baa4a7ed2971 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java @@ -66,14 +66,7 @@ class FileElementInfo extends SmartPointerElementInfo { @Override public boolean pointsToTheSameElementAs(@NotNull SmartPointerElementInfo other) { - if (other instanceof FileElementInfo) { - return Comparing.equal(myVirtualFile, ((FileElementInfo)other).myVirtualFile); - } - if (other instanceof SelfElementInfo || other instanceof ClsElementInfo) { - // optimisation: SelfElementInfo need psi (parsing) for element restoration and apriori could not reference psi file - return false; - } - return Comparing.equal(restoreElement(), other.restoreElement()); + return other instanceof FileElementInfo && Comparing.equal(myVirtualFile, ((FileElementInfo)other).myVirtualFile); } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java index 6fe4bbd8fe95..b8a8e04a990c 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/HardElementInfo.java @@ -15,10 +15,7 @@ */ package com.intellij.psi.impl.smartPointers; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Segment; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; @@ -57,12 +54,7 @@ class HardElementInfo extends SmartPointerElementInfo { @Override public boolean pointsToTheSameElementAs(@NotNull final SmartPointerElementInfo other) { - return Comparing.equal(myElement, ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiElement compute() { - return other.restoreElement(); - } - })); + return other instanceof HardElementInfo && myElement.equals(((HardElementInfo)other).myElement); } @Override diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java index 509fefb3da60..b441ade85b43 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java @@ -192,13 +192,7 @@ public class SelfElementInfo extends SmartPointerElementInfo { && range1.getEndOffset() == range2.getEndOffset(); }); } - return areRestoredElementsEqual(other); - } - - boolean areRestoredElementsEqual(@NotNull final SmartPointerElementInfo other) { - return ApplicationManager.getApplication().runReadAction( - (Computable)() -> Comparing.equal(getVirtualFile(), other.getVirtualFile()) - && Comparing.equal(restoreElement(), other.restoreElement())); + return false; } @Override diff --git a/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java b/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java index 72ab5b5d5b2b..390f8d7313af 100644 --- a/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java +++ b/platform/lang-api/src/com/intellij/execution/RunProfileStarter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,10 +31,12 @@ import static org.jetbrains.concurrency.Promises.rejectedPromise; */ public abstract class RunProfileStarter { @Nullable - public abstract RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException; + @Deprecated + public RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { + throw new AbstractMethodError(); + } /** - * Async version of {@link #execute(RunProfileState, ExecutionEnvironment)}. * You must NOT throw exceptions in this method. * Instead return {@link org.jetbrains.concurrency.Promises#rejectedPromise(Throwable)} or call {@link org.jetbrains.concurrency.AsyncPromise#setError(Throwable)} */ diff --git a/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java b/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java index 4fca1c097cb1..7d2c4f661236 100644 --- a/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java +++ b/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java @@ -16,23 +16,24 @@ package com.intellij.execution.runners; import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionManager; import com.intellij.execution.Executor; import com.intellij.execution.RunProfileStarter; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.configurations.RunnerSettings; -import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.concurrency.Promise; +import static com.intellij.execution.runners.GenericProgramRunnerKt.startRunProfile; + /** - * Allows to postpone actual {@link RunProfileState} execution until all the needed preparations are done. + * @deprecated Use AsyncProgramRunner */ +@Deprecated public abstract class AsyncGenericProgramRunner extends BaseProgramRunner { @Override - protected void execute(@NotNull ExecutionEnvironment environment, + protected final void execute(@NotNull ExecutionEnvironment environment, @Nullable Callback callback, @NotNull RunProfileState state) throws ExecutionException { prepare(environment, state) @@ -57,24 +58,4 @@ public abstract class AsyncGenericProgramRunner */ @NotNull protected abstract Promise prepare(@NotNull ExecutionEnvironment environment, @NotNull RunProfileState state) throws ExecutionException; - - private static void startRunProfile(@NotNull ExecutionEnvironment environment, - @NotNull RunProfileState state, - @Nullable final Callback callback, - @Nullable final RunProfileStarter starter) { - ExecutionManager.getInstance(environment.getProject()).startRunProfile(new RunProfileStarter() { - @Override - public Promise executeAsync(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) { - if (starter == null) { - return Promise.resolve(postProcess(environment, null, callback)); - } - return starter.executeAsync(state, environment).then(descriptor -> postProcess(environment, descriptor, callback)); - } - - @Override - public RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { - return postProcess(environment, starter == null ? null : starter.execute(state, environment), callback); - } - }, state, environment); - } } diff --git a/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java b/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java deleted file mode 100644 index 6119f76ee6b7..000000000000 --- a/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.execution.runners; - -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionManager; -import com.intellij.execution.RunProfileStarter; -import com.intellij.execution.configurations.RunProfileState; -import com.intellij.execution.configurations.RunnerSettings; -import com.intellij.execution.ui.RunContentDescriptor; -import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public abstract class GenericProgramRunner extends BaseProgramRunner { - @Override - protected void execute(@NotNull ExecutionEnvironment environment, @Nullable final Callback callback, @NotNull RunProfileState state) - throws ExecutionException { - ExecutionManager.getInstance(environment.getProject()).startRunProfile(new RunProfileStarter() { - @Override - public RunContentDescriptor execute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { - return postProcess(environment, doExecute(state, environment), callback); - } - }, state, environment); - } - - @Nullable - protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment environment) throws ExecutionException { - //noinspection deprecation - return doExecute(environment.getProject(), state, environment.getContentToReuse(), environment); - } - - /** - * @deprecated - */ - @SuppressWarnings({"unused", "DeprecatedIsStillUsed"}) - @Deprecated - @Nullable - protected RunContentDescriptor doExecute(@NotNull Project project, - @NotNull RunProfileState state, - @Nullable RunContentDescriptor contentToReuse, - @NotNull ExecutionEnvironment environment) throws ExecutionException { - throw new AbstractMethodError(); - } -} diff --git a/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.kt b/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.kt new file mode 100644 index 000000000000..745120df83c6 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/runners/GenericProgramRunner.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.runners + +import com.intellij.execution.ExecutionException +import com.intellij.execution.ExecutionManager +import com.intellij.execution.RunProfileStarter +import com.intellij.execution.configurations.RunProfileState +import com.intellij.execution.configurations.RunnerSettings +import com.intellij.execution.ui.RunContentDescriptor +import com.intellij.openapi.project.Project +import org.jetbrains.concurrency.Promise +import org.jetbrains.concurrency.resolvedPromise + +abstract class GenericProgramRunner : BaseProgramRunner() { + @Throws(ExecutionException::class) + override fun execute(environment: ExecutionEnvironment, callback: ProgramRunner.Callback?, state: RunProfileState) { + startRunProfile(environment, state, callback, runProfileStarter { resolvedPromise(doExecute(state, environment)) }) + } + + @Throws(ExecutionException::class) + protected open fun doExecute(state: RunProfileState, environment: ExecutionEnvironment): RunContentDescriptor? { + @Suppress("DEPRECATION") + return doExecute(environment.project, state, environment.contentToReuse, environment) + } + + @Deprecated("") + @Throws(ExecutionException::class) + protected open fun doExecute(project: Project, + state: RunProfileState, + contentToReuse: RunContentDescriptor?, + environment: ExecutionEnvironment): RunContentDescriptor? { + throw AbstractMethodError() + } +} + +abstract class AsyncProgramRunner : BaseProgramRunner() { + override final fun execute(environment: ExecutionEnvironment, callback: ProgramRunner.Callback?, state: RunProfileState) { + startRunProfile(environment, state, callback, runProfileStarter { execute(environment, state) }) + } + + @Throws(ExecutionException::class) + protected abstract fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise +} + +internal inline fun runProfileStarter(crossinline starter: () -> Promise) = object : RunProfileStarter() { + override fun executeAsync(state: RunProfileState, environment: ExecutionEnvironment) = starter() +} + +internal fun startRunProfile(environment: ExecutionEnvironment, state: RunProfileState, callback: ProgramRunner.Callback?, starter: RunProfileStarter?) { + ExecutionManager.getInstance(environment.project).startRunProfile(runProfileStarter { + (starter?.executeAsync(state, environment) ?: resolvedPromise()) + .then { BaseProgramRunner.postProcess(environment, it, callback) } + }, state, environment) +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index 91552bc6730e..01551afe262c 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -387,57 +387,58 @@ public class ExecutionManagerImpl extends ExecutionManager implements Disposable RunProfile profile = environment.getRunProfile(); project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarting(executor.getId(), environment); - starter.executeAsync(state, environment).done(descriptor -> { - AppUIUtil.invokeOnEdt(() -> { - if (descriptor != null) { - final Trinity trinity = - Trinity.create(descriptor, environment.getRunnerAndConfigurationSettings(), executor); - myRunningConfigurations.add(trinity); - Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity)); - getContentManager().showRunContent(executor, descriptor, environment.getContentToReuse()); - final ProcessHandler processHandler = descriptor.getProcessHandler(); - if (processHandler != null) { - if (!processHandler.isStartNotified()) { - processHandler.startNotify(); - } - project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(executor.getId(), environment, processHandler); + starter.executeAsync(state, environment) + .done(descriptor -> AppUIUtil.invokeLaterIfProjectAlive(project, () -> { + if (descriptor == null) { + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment); + return; + } - ProcessExecutionListener listener = new ProcessExecutionListener(project, executor.getId(), environment, processHandler, descriptor); - processHandler.addProcessListener(listener); + final Trinity trinity = + Trinity.create(descriptor, environment.getRunnerAndConfigurationSettings(), executor); + myRunningConfigurations.add(trinity); + Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity)); + getContentManager().showRunContent(executor, descriptor, environment.getContentToReuse()); + final ProcessHandler processHandler = descriptor.getProcessHandler(); + if (processHandler != null) { + if (!processHandler.isStartNotified()) { + processHandler.startNotify(); + } + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processStarted(executor.getId(), environment, processHandler); - // Since we cannot guarantee that the listener is added before process handled is start notified, - // we have to make sure the process termination events are delivered to the clients. - // Here we check the current process state and manually deliver events, while - // the ProcessExecutionListener guarantees each such event is only delivered once - // either by this code, or by the ProcessHandler. + ProcessExecutionListener + listener = new ProcessExecutionListener(project, executor.getId(), environment, processHandler, descriptor); + processHandler.addProcessListener(listener); - boolean terminating = processHandler.isProcessTerminating(); - boolean terminated = processHandler.isProcessTerminated(); - if (terminating || terminated) { - listener.processWillTerminate(new ProcessEvent(processHandler), false /*doesn't matter*/); + // Since we cannot guarantee that the listener is added before process handled is start notified, + // we have to make sure the process termination events are delivered to the clients. + // Here we check the current process state and manually deliver events, while + // the ProcessExecutionListener guarantees each such event is only delivered once + // either by this code, or by the ProcessHandler. - if (terminated) { - //noinspection ConstantConditions - int exitCode = processHandler.isStartNotified() ? processHandler.getExitCode() : -1; - listener.processTerminated(new ProcessEvent(processHandler, exitCode)); - } + boolean terminating = processHandler.isProcessTerminating(); + boolean terminated = processHandler.isProcessTerminated(); + if (terminating || terminated) { + listener.processWillTerminate(new ProcessEvent(processHandler), false /*doesn't matter*/); + + if (terminated) { + //noinspection ConstantConditions + int exitCode = processHandler.isStartNotified() ? processHandler.getExitCode() : -1; + listener.processTerminated(new ProcessEvent(processHandler, exitCode)); } } - environment.setContentToReuse(descriptor); } - else { - project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment); + environment.setContentToReuse(descriptor); + })) + .rejected(e -> { + if (!(e instanceof ProcessCanceledException)) { + ExecutionException error = e instanceof ExecutionException ? (ExecutionException)e : new ExecutionException(e); + ExecutionUtil.handleExecutionError(project, ExecutionManager.getInstance(project).getContentManager().getToolWindowIdByEnvironment(environment), + profile, error); } - }, o -> project.isDisposed()); - }).rejected(e -> { - if (!(e instanceof ProcessCanceledException)) { - ExecutionException error = e instanceof ExecutionException ? (ExecutionException)e : new ExecutionException(e); - ExecutionUtil.handleExecutionError(project, ExecutionManager.getInstance(project).getContentManager().getToolWindowIdByEnvironment(environment), - profile, error); - } - LOG.info(e); - project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment); - }); + LOG.info(e); + project.getMessageBus().syncPublisher(EXECUTION_TOPIC).processNotStarted(executor.getId(), environment); + }); }; if (ApplicationManager.getApplication().isUnitTestMode() && !myForceCompilationInTests) { diff --git a/platform/lang-impl/src/com/intellij/execution/runners/DefaultProgramRunner.kt b/platform/lang-impl/src/com/intellij/execution/runners/DefaultProgramRunner.kt index dd4df4942aea..f6aa70d41c59 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/DefaultProgramRunner.kt +++ b/platform/lang-impl/src/com/intellij/execution/runners/DefaultProgramRunner.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package com.intellij.execution.runners import com.intellij.execution.ExecutionException import com.intellij.execution.ExecutionResult -import com.intellij.execution.RunProfileStarter import com.intellij.execution.configurations.RunProfileState import com.intellij.execution.configurations.RunnerSettings import com.intellij.execution.ui.RunContentDescriptor @@ -25,15 +24,11 @@ import com.intellij.openapi.fileEditor.FileDocumentManager abstract class DefaultProgramRunner : GenericProgramRunner() { @Throws(ExecutionException::class) - override fun doExecute(state: RunProfileState, env: ExecutionEnvironment): RunContentDescriptor? { - return executeState(state, env, this) + override fun doExecute(state: RunProfileState, environment: ExecutionEnvironment): RunContentDescriptor? { + return executeState(state, environment, this) } } -inline fun runProfileStarter(crossinline starter: (state: RunProfileState, environment: ExecutionEnvironment) -> RunContentDescriptor?) = object : RunProfileStarter() { - override fun execute(state: RunProfileState, env: ExecutionEnvironment) = starter(state, env) -} - internal fun executeState(state: RunProfileState, env: ExecutionEnvironment, runner: ProgramRunner<*>): RunContentDescriptor? { FileDocumentManager.getInstance().saveAllDocuments() return showRunContent(state.execute(env.executor, runner), env) diff --git a/platform/lang-impl/src/com/intellij/execution/runners/DefaultRunProgramRunner.kt b/platform/lang-impl/src/com/intellij/execution/runners/DefaultRunProgramRunner.kt index 849258ad2f02..9f5adc71f684 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/DefaultRunProgramRunner.kt +++ b/platform/lang-impl/src/com/intellij/execution/runners/DefaultRunProgramRunner.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.intellij.execution.runners -import com.intellij.execution.RunProfileStarter import com.intellij.execution.configurations.RunProfile import com.intellij.execution.configurations.RunProfileState import com.intellij.execution.configurations.RunnerSettings @@ -25,29 +24,23 @@ import com.intellij.openapi.fileEditor.FileDocumentManager import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.resolvedPromise -private class DefaultRunProgramRunner : AsyncGenericProgramRunner() { +private class DefaultRunProgramRunner : AsyncProgramRunner() { override fun getRunnerId() = "defaultRunRunner" - override fun prepare(environment: ExecutionEnvironment, state: RunProfileState): Promise { - return resolvedPromise(object : RunProfileStarter() { - override fun execute(state: RunProfileState, environment: ExecutionEnvironment): RunContentDescriptor? { - FileDocumentManager.getInstance().saveAllDocuments() - return showRunContent(state.execute(environment.executor, this@DefaultRunProgramRunner), environment) - } - - override fun executeAsync(state: RunProfileState, environment: ExecutionEnvironment): Promise { - if (state is DebuggableRunProfileState) { - FileDocumentManager.getInstance().saveAllDocuments() - return state.execute(-1) - .then { - it?.let { - RunContentBuilder(it, environment).showRunContent(environment.contentToReuse) - } - } + override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise { + FileDocumentManager.getInstance().saveAllDocuments() + @Suppress("IfThenToElvis") + if (state is DebuggableRunProfileState) { + return state.execute(-1) + .then { + it?.let { + RunContentBuilder(it, environment).showRunContent(environment.contentToReuse) + } } - return super.executeAsync(state, environment) - } - }) + } + else { + return resolvedPromise(showRunContent(state.execute(environment.executor, this@DefaultRunProgramRunner), environment)) + } } override fun canRun(executorId: String, profile: RunProfile): Boolean { diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java b/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java index 62edc1fd0fbf..aadc765b3edf 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/TreeState.java @@ -213,7 +213,9 @@ public class TreeState implements JDOMExternalizable { //nodeDescriptor.update(); result.add(new PathElement(getDescriptorKey(nodeDescriptor), getDescriptorType(nodeDescriptor), childIndex, nodeDescriptor)); } - result.add(new PathElement("", "", childIndex, userObject)); + else { + result.add(new PathElement("", "", childIndex, userObject)); + } } else { return null; diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapImpl.kt b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapImpl.kt index 514a10548702..8b33cee35a73 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -349,36 +349,9 @@ open class KeymapImpl @JvmOverloads constructor(private var dataHolder: SchemeDa } return sortInRegistrationOrder(list) } - - override fun getActionIds(firstKeyStroke: KeyStroke): Array { - // first, get keystrokes from own map - var list = keystrokeToIds.get(firstKeyStroke) - val ids = parent?.getActionIds(convertKeyStroke(firstKeyStroke)) - if (ids != null && ids.isNotEmpty()) { - var isOriginalListInstance = list != null - for (id in ids) { - // add actions from parent keymap only if they are absent in this keymap - // do not add parent bind actions, if bind-on action is overwritten in the child - if (actionIdToShortcuts.containsKey(id) || actionIdToShortcuts.containsKey(keymapManager.getActionBinding(id))) { - continue - } - - if (list == null) { - list = SmartList() - } - else if (isOriginalListInstance) { - list = SmartList(list) - isOriginalListInstance = false - } - - if (!list.contains(id)) { - list.add(id) - } - } - } - return sortInRegistrationOrder(list) - } - + + override fun getActionIds(firstKeyStroke: KeyStroke) = getActionIds(firstKeyStroke, { keystrokeToIds }, { convertKeyStroke(it) }) + override fun getActionIds(firstKeyStroke: KeyStroke, secondKeyStroke: KeyStroke?): Array { val ids = getActionIds(firstKeyStroke) var actualBindings: MutableList? = null @@ -428,17 +401,19 @@ open class KeymapImpl @JvmOverloads constructor(private var dataHolder: SchemeDa } while (true) } - - override fun getActionIds(shortcut: MouseShortcut): Array { - var list = mouseShortcutToActionIds.get(shortcut) + + override fun getActionIds(shortcut: MouseShortcut) = getActionIds(shortcut, { mouseShortcutToActionIds }, { convertMouseShortcut(it) }) + + private inline fun getActionIds(shortcut: T, shortcutToActionsIds: KeymapImpl.() -> Map>, convertShortcut: KeymapImpl.(shortcut: T) -> T): Array { + var list = shortcutToActionsIds().get(shortcut) var parent = parent ?: return sortInRegistrationOrder(list) - + var originalListInstance = list != null var child = this - var convertedShortcut = convertMouseShortcut(shortcut) + var convertedShortcut = convertShortcut(shortcut) do { - for (id in (parent.mouseShortcutToActionIds.get(convertedShortcut) ?: emptyList())) { - if (child.actionIdToShortcuts.containsKey(id)) { + for (id in (parent.shortcutToActionsIds().get(convertedShortcut)?.sortInRegistrationOrder() ?: emptyList())) { + if (child.actionIdToShortcuts.containsKey(id) || actionIdToShortcuts.containsKey(keymapManager.getActionBinding(id))) { // on remove shortcut we put empty list to actionIdToShortcuts, our mouseShortcutToActionIds doesn't contain mapping // so, we add actions from parent keymap only if they are absent in this keymap continue @@ -452,14 +427,15 @@ open class KeymapImpl @JvmOverloads constructor(private var dataHolder: SchemeDa } else if (originalListInstance) { list = SmartList(list) + list.sortWith(ActionManagerEx.getInstanceEx().registrationOrderComparator) originalListInstance = false } list.add(id) } child = parent - parent = child.parent ?: return sortInRegistrationOrder(list) - convertedShortcut = child.convertMouseShortcut(shortcut) + parent = child.parent ?: return ArrayUtilRt.toStringArray(list) + convertedShortcut = child.convertShortcut(shortcut) } while (true) } @@ -733,6 +709,13 @@ private fun sortInRegistrationOrder(ids: List?): Array { return array } +private fun List.sortInRegistrationOrder(): List { + if (size > 1) { + return sortedWith(ActionManagerEx.getInstanceEx().registrationOrderComparator) + } + return this +} + // compare two lists in any order private fun areShortcutsEqual(shortcuts1: List, shortcuts2: List): Boolean { if (shortcuts1.size != shortcuts2.size) { diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/KeymapTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/KeymapTest.java index 5a3be02ef8c0..14d9b07632b5 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/KeymapTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/KeymapTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -163,6 +163,18 @@ public class KeymapTest extends PlatformTestCase { myChild.removeShortcut(ACTION_2, mouseShortcut); assertThat(myChild.getActionIds(mouseShortcut)).isEmpty(); } + + public void testChangeMouseShortcut() throws Exception { + myParent.clearOwnActionsIds(); + myChild.clearOwnActionsIds(); + + MouseShortcut mouseShortcut = new MouseShortcut(1, InputEvent.BUTTON2_MASK, 1); + myParent.addShortcut(ACTION_1, mouseShortcut); + assertThat(myChild.getActionIds(mouseShortcut)).containsExactly(ACTION_1); + + myChild.addShortcut(ACTION_2, mouseShortcut); + assertThat(myChild.getActionIds(mouseShortcut)).containsExactly(ACTION_2, ACTION_1); + } public void testRemovingShortcutLast() throws Exception { myParent.clearOwnActionsIds(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java index 6ee8cebccd6f..2218485c6e10 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java @@ -20,9 +20,9 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.BackgroundTaskQueue; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; @@ -30,7 +30,6 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.index.VcsLogIndex; @@ -59,7 +58,6 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { @NotNull private final Project myProject; @NotNull private final Map myLogProviders; - @NotNull private final BackgroundTaskQueue myDataLoaderQueue; @NotNull private final MiniDetailsGetter myMiniDetailsGetter; @NotNull private final CommitDetailsGetter myDetailsGetter; @@ -90,7 +88,6 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { @NotNull FatalErrorHandler fatalErrorsConsumer) { myProject = project; myLogProviders = logProviders; - myDataLoaderQueue = new BackgroundTaskQueue(project, "Loading history..."); myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(project, VcsUserRegistry.class); myFatalErrorsConsumer = fatalErrorsConsumer; @@ -137,6 +134,42 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { return hashMap; } + public void initialize() { + StopWatch stopWatch = StopWatch.start("initialize"); + Task.Backgroundable backgroundable = new Task.Backgroundable(myProject, "Loading History...", false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + indicator.setIndeterminate(true); + resetState(); + readCurrentUser(); + DataPack dataPack = myRefresher.readFirstBlock(); + fireDataPackChangeEvent(dataPack); + stopWatch.report(); + } + }; + ProgressManager.getInstance().runProcessWithProgressAsynchronously(backgroundable, myRefresher.getProgress().createProgressIndicator()); + } + + private void readCurrentUser() { + StopWatch sw = StopWatch.start("readCurrentUser"); + for (Map.Entry entry : myLogProviders.entrySet()) { + VirtualFile root = entry.getKey(); + try { + VcsUser me = entry.getValue().getCurrentUser(root); + if (me != null) { + myCurrentUser.put(root, me); + } + else { + LOG.info("Username not configured for root " + root); + } + } + catch (VcsException e) { + LOG.warn("Couldn't read the username from root " + root, e); + } + } + sw.report(); + } + private void fireDataPackChangeEvent(@NotNull final DataPack dataPack) { ApplicationManager.getApplication().invokeLater(() -> { for (DataPackChangeListener listener : myDataPackChangeListeners) { @@ -174,39 +207,6 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { return myStorage; } - public void initialize() { - final StopWatch initSw = StopWatch.start("initialize"); - myDataLoaderQueue.clear(); - - runInBackground(indicator -> { - resetState(); - readCurrentUser(); - DataPack dataPack = myRefresher.readFirstBlock(); - fireDataPackChangeEvent(dataPack); - initSw.report(); - }); - } - - private void readCurrentUser() { - StopWatch sw = StopWatch.start("readCurrentUser"); - for (Map.Entry entry : myLogProviders.entrySet()) { - VirtualFile root = entry.getKey(); - try { - VcsUser me = entry.getValue().getCurrentUser(root); - if (me != null) { - myCurrentUser.put(root, me); - } - else { - LOG.info("Username not configured for root " + root); - } - } - catch (VcsException e) { - LOG.warn("Couldn't read the username from root " + root, e); - } - } - sw.report(); - } - private void resetState() { myTopCommitsDetailsCache.clear(); } @@ -241,22 +241,6 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { return myContainingBranchesGetter; } - private void runInBackground(@NotNull ThrowableConsumer task) { - Task.Backgroundable backgroundable = new Task.Backgroundable(myProject, "Loading History...", false) { - @Override - public void run(@NotNull ProgressIndicator indicator) { - indicator.setIndeterminate(true); - try { - task.consume(indicator); - } - catch (VcsException e) { - throw new RuntimeException(e); // TODO - } - } - }; - myDataLoaderQueue.run(backgroundable, null, myRefresher.getProgress().createProgressIndicator()); - } - /** * Refreshes specified roots. * Does not re-read all log but rather the most recent commits. @@ -286,7 +270,6 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { @Override public void dispose() { - myDataLoaderQueue.clear(); resetState(); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java index 6a043ea331f0..881170e938f3 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java @@ -40,6 +40,7 @@ public class VcsLogProgress implements Disposable { return createProgressIndicator(true); } + @NotNull public ProgressIndicator createProgressIndicator(boolean visible) { if (ApplicationManager.getApplication().isHeadlessEnvironment()) { return new EmptyProgressIndicator(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java index 06812c5263b8..114d29724c78 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java @@ -24,7 +24,6 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.Function; import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; @@ -166,13 +165,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { @NotNull private List> compactCommits(@NotNull List commits, @NotNull final VirtualFile root) { StopWatch sw = StopWatch.start("compacting commits"); - List> map = ContainerUtil.map(commits, new Function>() { - @NotNull - @Override - public GraphCommit fun(@NotNull TimedVcsCommit commit) { - return compactCommit(commit, root); - } - }); + List> map = ContainerUtil.map(commits, commit -> compactCommit(commit, root)); myStorage.flush(); sw.report(); return map; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java index a19880de2462..a0a002f9d46a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/BlockUtils.java @@ -21,31 +21,38 @@ import com.intellij.psi.*; * @author Tagir Valeev */ public class BlockUtils { + /** - * Add new statement before given anchor statement creating code block, if necessary + * Adds new statements before given anchor statement creating a new code block, if necessary * - * @param anchor existing statement - * @param newStatement a new statement which should be added before an existing one - * @return added physical statement + * @param anchor existing statement + * @param newStatements the new statements which should be added before the existing one + * @return last added physical statement */ - public static PsiStatement addBefore(PsiStatement anchor, PsiStatement newStatement) { + public static PsiStatement addBefore(PsiStatement anchor, PsiStatement... newStatements) { + if (newStatements.length == 0) throw new IllegalArgumentException(); PsiElement oldStatement = anchor; PsiElement parent = oldStatement.getParent(); while (parent instanceof PsiLabeledStatement) { oldStatement = parent; parent = oldStatement.getParent(); } - final PsiElement result; + PsiElement result = null; if (parent instanceof PsiCodeBlock) { - result = parent.addBefore(newStatement, oldStatement); + for (PsiStatement statement : newStatements) { + result = parent.addBefore(statement, oldStatement); + } } else { - PsiElementFactory factory = JavaPsiFacade.getElementFactory(anchor.getProject()); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(anchor.getProject()); final PsiBlockStatement newBlockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", oldStatement); final PsiElement codeBlock = newBlockStatement.getCodeBlock(); - codeBlock.add(newStatement); + for (PsiStatement newStatement : newStatements) { + codeBlock.add(newStatement); + } codeBlock.add(oldStatement); - result = ((PsiBlockStatement)oldStatement.replace(newBlockStatement)).getCodeBlock().getStatements()[0]; + final PsiStatement[] statements = ((PsiBlockStatement)oldStatement.replace(newBlockStatement)).getCodeBlock().getStatements(); + result = statements[statements.length - 2]; } return (PsiStatement)result; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java index 1d1630596908..986bbbb3ac4a 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2016 Bas Leijdekkers + * Copyright 2006-2017 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,14 @@ package com.siyeh.ipp.forloop; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.ig.psiutils.BlockUtils; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + public class ReplaceForLoopWithWhileLoopIntention extends Intention { @Override @@ -40,7 +43,6 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { final PsiWhileStatement whileStatement = (PsiWhileStatement)factory.createStatementFromText("while(true) {}", element); final PsiExpression forCondition = forStatement.getCondition(); final PsiExpression whileCondition = whileStatement.getCondition(); - final PsiStatement body = forStatement.getBody(); if (forCondition != null) { assert whileCondition != null; whileCondition.replace(forCondition); @@ -49,17 +51,18 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { if (blockStatement == null) { return; } - final PsiElement newBody; - if (body instanceof PsiBlockStatement) { - final PsiBlockStatement newWhileBody = (PsiBlockStatement)blockStatement.replace(body); - newBody = newWhileBody.getCodeBlock(); + final PsiStatement forStatementBody = forStatement.getBody(); + final PsiElement loopBody; + if (forStatementBody instanceof PsiBlockStatement) { + final PsiBlockStatement newWhileBody = (PsiBlockStatement)blockStatement.replace(forStatementBody); + loopBody = newWhileBody.getCodeBlock(); } else { final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); - if (body != null && !(body instanceof PsiEmptyStatement)) { - codeBlock.addAfter(body, codeBlock.getFirstChild()); + if (forStatementBody != null && !(forStatementBody instanceof PsiEmptyStatement)) { + codeBlock.add(forStatementBody); } - newBody = codeBlock; + loopBody = codeBlock; } final PsiStatement update = forStatement.getUpdate(); if (update != null) { @@ -69,53 +72,29 @@ public class ReplaceForLoopWithWhileLoopIntention extends Intention { final PsiExpressionList expressionList = expressionListStatement.getExpressionList(); final PsiExpression[] expressions = expressionList.getExpressions(); updateStatements = new PsiStatement[expressions.length]; - for (int i = 0, expressionsLength = expressions.length; i < expressionsLength; i++) { - final PsiExpression expression = expressions[i]; - final PsiStatement updateStatement = factory.createStatementFromText(expression.getText() + ';', element); - updateStatements[i] = updateStatement; + for (int i = 0; i < expressions.length; i++) { + updateStatements[i] = factory.createStatementFromText(expressions[i].getText() + ';', element); } } else { final PsiStatement updateStatement = factory.createStatementFromText(update.getText() + ';', element); updateStatements = new PsiStatement[]{updateStatement}; } - newBody.accept(new UpdateInserter(whileStatement, updateStatements)); + final Collection continueStatements = PsiTreeUtil.findChildrenOfType(loopBody, PsiContinueStatement.class); + for (PsiContinueStatement continueStatement : continueStatements) { + BlockUtils.addBefore(continueStatement, updateStatements); + } for (PsiStatement updateStatement : updateStatements) { - newBody.addBefore(updateStatement, newBody.getLastChild()); + loopBody.addBefore(updateStatement, loopBody.getLastChild()); } } if (initialization == null || initialization instanceof PsiEmptyStatement) { - return; + forStatement.replace(whileStatement); } - initialization = (PsiStatement)initialization.copy(); - PsiElement newElement = forStatement.replace(whileStatement); - BlockUtils.addBefore((PsiStatement)newElement, initialization); - } - - private static class UpdateInserter extends JavaRecursiveElementWalkingVisitor { - - private final PsiWhileStatement whileStatement; - private final PsiStatement[] updateStatements; - - private UpdateInserter(PsiWhileStatement whileStatement, PsiStatement[] updateStatements) { - this.whileStatement = whileStatement; - this.updateStatements = updateStatements; - } - - @Override - public void visitContinueStatement(PsiContinueStatement statement) { - final PsiStatement continuedStatement = statement.findContinuedStatement(); - if (!whileStatement.equals(continuedStatement)) { - return; - } - final PsiElement parent = statement.getParent(); - if (parent == null) { - return; - } - for (PsiStatement updateStatement : updateStatements) { - parent.addBefore(updateStatement, statement); - } - super.visitContinueStatement(statement); + else { + initialization = (PsiStatement)initialization.copy(); + final PsiStatement newStatement = (PsiStatement)forStatement.replace(whileStatement); + BlockUtils.addBefore(newStatement, initialization); } } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/whileloop/ExtractWhileLoopConditionToIfStatementIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/whileloop/ExtractWhileLoopConditionToIfStatementIntention.java index 00acf9954d34..be2f99f26f45 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/whileloop/ExtractWhileLoopConditionToIfStatementIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/whileloop/ExtractWhileLoopConditionToIfStatementIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 Bas Leijdekkers + * Copyright 2007-2017 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,22 +17,21 @@ package com.siyeh.ipp.whileloop; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.util.IncorrectOperationException; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; public class ExtractWhileLoopConditionToIfStatementIntention extends Intention { + @Override @NotNull protected PsiElementPredicate getElementPredicate() { return new WhileLoopPredicate(); } - protected void processIntention(@NotNull PsiElement element) - throws IncorrectOperationException { - final PsiWhileStatement whileStatement = - (PsiWhileStatement)element.getParent(); + @Override + protected void processIntention(@NotNull PsiElement element) { + final PsiWhileStatement whileStatement = (PsiWhileStatement)element.getParent(); if (whileStatement == null) { return; } @@ -43,14 +42,9 @@ public class ExtractWhileLoopConditionToIfStatementIntention extends Intention { final String conditionText = condition.getText(); final PsiManager manager = whileStatement.getManager(); final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - final PsiExpression newCondition = - factory.createExpressionFromText("true", whileStatement); - condition.replace(newCondition); + condition.replace(factory.createExpressionFromText("true", whileStatement)); final PsiStatement body = whileStatement.getBody(); - final String ifStatementText = "if (!(" + conditionText + ")) break;"; - final PsiStatement ifStatement = - factory.createStatementFromText(ifStatementText, - whileStatement); + final PsiStatement ifStatement = factory.createStatementFromText("if (!(" + conditionText + ")) break;", whileStatement); final PsiElement newElement; if (body instanceof PsiBlockStatement) { final PsiBlockStatement blockStatement = (PsiBlockStatement)body; @@ -59,9 +53,7 @@ public class ExtractWhileLoopConditionToIfStatementIntention extends Intention { newElement = codeBlock.addBefore(ifStatement, bodyElement); } else if (body != null) { - final PsiBlockStatement blockStatement = - (PsiBlockStatement)factory.createStatementFromText("{}", - whileStatement); + final PsiBlockStatement blockStatement = (PsiBlockStatement)factory.createStatementFromText("{}", whileStatement); final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); codeBlock.add(ifStatement); if (!(body instanceof PsiEmptyStatement)) { diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java new file mode 100644 index 000000000000..2925e6ef71e6 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing.java @@ -0,0 +1,8 @@ +class Continuing { + void testFor() { + for (int i=0; i<10; i++) { + if(i == 5) continue; + System.out.println(i); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java new file mode 100644 index 000000000000..fa6b9cbcc70c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/Continuing_after.java @@ -0,0 +1,13 @@ +class Continuing { + void testFor() { + int i=0; + while (i<10) { + if(i == 5) { + i++; + continue; + } + System.out.println(i); + i++; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java new file mode 100644 index 000000000000..b7a7fcbf3788 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit.java @@ -0,0 +1,7 @@ +class NoInit{ + void m(int i) { + for (; i < 100; i++) { + + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java new file mode 100644 index 000000000000..8146d187862f --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/forloop/while_loop/NoInit_after.java @@ -0,0 +1,8 @@ +class NoInit{ + void m(int i) { + while (i < 100) { + + i++; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java index ed9a294443c0..c3f803d7433e 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/forloop/ReplaceForLoopWithWhileLoopIntentionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ public class ReplaceForLoopWithWhileLoopIntentionTest extends IPPTestCase { public void testNotInBlock() { doTest(); } public void testDoubleLabelNoBraces() { doTest(); } public void testUpdatingMuch() { doTest(); } + public void testContinuing() { doTest(); } + public void testNoInit() { doTest(); } @Override protected String getIntentionName() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 561feda63191..27db8b6fe64b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1222,6 +1222,8 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla .map(PyWithItem::getTarget) .select(PyTargetExpression.class) .forEach(result::add); + + super.visitPyWithStatement(node); } }); return result; diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/instanceAttributeCreatedInsideWithStatement.py b/python/testData/inspections/PyUnresolvedReferencesInspection/instanceAttributeCreatedInsideWithStatement.py new file mode 100644 index 000000000000..fd25530a1870 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/instanceAttributeCreatedInsideWithStatement.py @@ -0,0 +1,8 @@ +class Foo(object): + def __init__(self): + with open('b.py'): + self.scope = "a" + pass + + def get_scope(self): + return self.scope \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 807e879d85ef..0b4da8a34b8e 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -758,6 +758,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { assertNotParsed((PyFile)fooPsiFile); } + // PY-23164 + public void testInstanceAttributeCreatedInsideWithStatement() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { diff --git a/xml/tests/src/com/intellij/editor/XmlEditorTest.java b/xml/tests/src/com/intellij/editor/XmlEditorTest.java index 3fa13f00492b..73fcd4c7097a 100644 --- a/xml/tests/src/com/intellij/editor/XmlEditorTest.java +++ b/xml/tests/src/com/intellij/editor/XmlEditorTest.java @@ -34,12 +34,14 @@ public class XmlEditorTest extends LightCodeInsightTestCase { public void testEnterPerformance() throws Exception { configureByFile(getTestFilePath(true)); - EditorTestUtil.performTypingAction(myEditor, '\n'); + for (int i = 0; i < 3; i++) { + EditorTestUtil.performTypingAction(myEditor, '\n'); + } PlatformTestUtil.startPerformanceTest("Xml editor enter", 7500, () -> { for (int i = 0; i < 3; i ++) { EditorTestUtil.performTypingAction(myEditor, '\n'); } - }).cpuBound().assertTiming(); + }).cpuBound().attempts(1).assertTiming(); checkResultByFile(getTestFilePath(false)); } diff --git a/xml/tests/testData/editor/enterPerformance_after.xml b/xml/tests/testData/editor/enterPerformance_after.xml index dbc2847af13b..d42a0c63386b 100644 --- a/xml/tests/testData/editor/enterPerformance_after.xml +++ b/xml/tests/testData/editor/enterPerformance_after.xml @@ -19829,6 +19829,8 @@ + +