dispose before project will be disposed, otherwise cannot publish to message bus

GitOrigin-RevId: 45a9e856f5b477e29bb13307fac10d4714e484d1
This commit is contained in:
Vladimir Krivosheev
2019-11-26 10:40:24 +00:00
committed by intellij-monorepo-bot
parent 64760ffe0b
commit 32ae4f4b20
14 changed files with 105 additions and 59 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.propertyBased;
import com.intellij.application.options.CodeStyle;
@@ -59,7 +59,7 @@ public class JavaCodeInsightSanityTest extends LightJavaCodeInsightFixtureTestCa
}
private void enableInspections() {
MadTestingUtil.enableAllInspections(getProject(), getTestRootDisposable());
MadTestingUtil.enableAllInspections(getProject());
}
public void testPreserveComments() {
@@ -47,7 +47,7 @@ public class JavaSwitchExpressionSanityTest extends LightJavaCodeInsightFixtureT
}
public void testIntentionsAroundSwitch() {
MadTestingUtil.enableAllInspections(getProject(), getTestRootDisposable(), "BoundedWildcard"); // IDEA-194460
MadTestingUtil.enableAllInspections(getProject(), "BoundedWildcard"); // IDEA-194460
Function<PsiFile, Generator<? extends MadTestingAction>> fileActions =
file -> {
@@ -1,25 +1,13 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.propertyBased;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.psi.*;
@@ -49,7 +37,20 @@ public class UnivocityTest extends AbstractApplyAndRevertTestCase {
public void setUp() throws Exception {
super.setUp();
((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).disableBackgroundCommit(getTestRootDisposable());
MadTestingUtil.enableAllInspections(myProject, myProject);
MadTestingUtil.enableAllInspections(myProject);
}
@Override
public void tearDown() throws Exception {
try {
Disposer.dispose(((ProjectEx)myProject).getEarlyDisposable());
}
catch (Throwable e) {
addSuppressedException(e);
}
finally {
super.tearDown();
}
}
public void testCompilabilityAfterIntentions() {
@@ -1,8 +1,10 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.project.ex;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -28,4 +30,20 @@ public interface ProjectEx extends Project {
default boolean isLight() {
return false;
}
/**
* {@link Disposable} that will be disposed right after container started to be disposed.
* Use it to dispose something that need to be disposed very early, e.g. {@link com.intellij.util.Alarm}.
* Or, only and only in unit test mode, if you need to publish something to message bus during dispose.<p/>
*
* In unit test mode light project is not disposed, but this disposable is disposed for each test.
* So, you don't need to have another disposable and can use this one instead.<p/>
*
* Dependent {@link Disposable#dispose} may be called in any thread.
* Implementation of {@link Disposable#dispose} must be self-contained and isolated (getting services is forbidden, publishing to message bus is allowed only in tests).
*/
@NotNull
@ApiStatus.Experimental
@ApiStatus.Internal
Disposable getEarlyDisposable();
}
@@ -29,7 +29,7 @@ import java.util.List;
/**
* @author peter
*/
final class DefaultProject extends UserDataHolderBase implements ProjectEx, ProjectStoreOwner {
final class DefaultProject extends UserDataHolderBase implements Project, ProjectStoreOwner {
private static final Logger LOG = Logger.getInstance(DefaultProject.class);
private final DefaultProjectTimed myDelegate = new DefaultProjectTimed(this) {
@@ -129,11 +129,6 @@ final class DefaultProject extends UserDataHolderBase implements ProjectEx, Proj
return myDelegate.isCached();
}
@Override
public void setProjectName(@NotNull String name) {
throw new IllegalStateException();
}
// delegates
@Override
@NotNull
@@ -9,6 +9,7 @@ import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.startup.StartupManagerEx;
import com.intellij.idea.ApplicationLoader;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -30,6 +31,7 @@ import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -47,6 +49,7 @@ import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
public class ProjectImpl extends PlatformComponentManagerImpl implements ProjectEx, ProjectStoreOwner {
private static final Logger LOG = Logger.getInstance(ProjectImpl.class);
@@ -64,6 +67,9 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
private final String creationTrace;
private ProjectStoreFactory myProjectStoreFactory;
private final AtomicReference<Disposable> earlyDisposable = new AtomicReference<>(Disposer.newDisposable());
private volatile boolean temporarilyDisposed;
private final AtomicNotNullLazyValue<IComponentStore> myComponentStore = AtomicNotNullLazyValue.createValue(() -> {
ProjectStoreFactory factory = myProjectStoreFactory != null ? myProjectStoreFactory : ServiceManager.getService(ProjectStoreFactory.class);
return factory.createStore(this);
@@ -111,13 +117,23 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
return myLight;
}
private volatile boolean temporarilyDisposed;
@TestOnly
void setTemporarilyDisposed(boolean value) {
if (!value && super.isDisposed()) {
LOG.error("Project was already disposed, flag temporarilyDisposed cannot be set to `true`");
if (temporarilyDisposed == value) {
return;
}
if (value && super.isDisposed()) {
throw new IllegalStateException("Project was already disposed, flag temporarilyDisposed cannot be set to `true`");
}
if (!value) {
Disposable newDisposable = Disposer.newDisposable();
if (!earlyDisposable.compareAndSet(null, newDisposable)) {
throw new IllegalStateException("earlyDisposable must be null on second opening of light project");
}
}
temporarilyDisposed = value;
}
@@ -337,8 +353,6 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
@Override
public synchronized void dispose() {
setDisposeInProgress();
Application application = ApplicationManager.getApplication();
application.assertWriteAccessAllowed(); // dispose must be under write action
@@ -386,6 +400,25 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
return "project ";
}
@Override
@NotNull
@ApiStatus.Experimental
@ApiStatus.Internal
public final Disposable getEarlyDisposable() {
if (isDisposed()) {
throw new IllegalStateException(this + " is disposed already");
}
// maybe null only if disposed, but this condition is checked above
return earlyDisposable.get();
}
@ApiStatus.Internal
public final void disposeEarlyDisposable() {
Disposable earlyDisposable = this.earlyDisposable.getAndSet(null);
Disposer.dispose(earlyDisposable);
}
@ApiStatus.Internal
public final void setDisposeInProgress() {
myContainerState.set(ContainerState.DISPOSE_IN_PROGRESS);
@@ -689,9 +689,10 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
// if we are shutting down the entire test framework, proceed to full dispose
ProjectImpl projectImpl = (ProjectImpl)project;
if (!projectImpl.isTemporarilyDisposed()) {
projectImpl.disposeEarlyDisposable();
projectImpl.setTemporarilyDisposed(true);
removeFromOpened(project);
((ProjectManagerImpl)ProjectManager.getInstance()).updateTheOnlyProjectField();
updateTheOnlyProjectField();
return true;
}
projectImpl.setTemporarilyDisposed(false);
@@ -725,6 +726,11 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
// somebody can start progress here, do not wrap in write action
fireProjectClosing(project);
// ignore dispose flag
if (project instanceof ProjectImpl) {
((ProjectImpl)project).disposeEarlyDisposable();
}
app.runWriteAction(() -> {
if (dispose && project instanceof ProjectImpl) {
((ProjectImpl)project).setDisposeInProgress();
@@ -14,4 +14,10 @@ public class MockProjectEx extends MockProject implements ProjectEx {
@Override
public void setProjectName(@NotNull String name) {
}
@NotNull
@Override
public final Disposable getEarlyDisposable() {
return this;
}
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.Inlay;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -656,6 +657,6 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
*/
@NotNull
default Disposable getProjectDisposable() {
return getProject();
return ((ProjectEx)getProject()).getEarlyDisposable();
}
}
@@ -4,6 +4,8 @@ package com.intellij.testFramework.fixtures;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.impl.ProjectImpl;
import org.jetbrains.annotations.NotNull;
/**
@@ -19,6 +21,6 @@ public interface IdeaProjectTestFixture extends IdeaTestFixture {
@NotNull
default Disposable getTestRootDisposable() {
return getProject();
return ((ProjectEx)getProject()).getEarlyDisposable();
}
}
@@ -2057,5 +2057,4 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
public Disposable getProjectDisposable() {
return myProjectFixture.getTestRootDisposable();
}
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
@@ -63,7 +64,7 @@ import java.util.stream.Stream;
/**
* @author peter
*/
public class MadTestingUtil {
public final class MadTestingUtil {
private static final Logger LOG = Logger.getInstance(MadTestingUtil.class);
private static final boolean USE_ROULETTE_WHEEL = true;
@@ -169,7 +170,7 @@ public class MadTestingUtil {
* @param disposable when this is disposed, reverts to the previous project inspection profile
* @param except short names of inspections to disable
*/
public static void enableAllInspections(Project project, Disposable disposable, String... except) {
public static void enableAllInspections(@NotNull Project project, String... except) {
InspectionProfileImpl.INIT_INSPECTIONS = true;
InspectionProfileImpl profile = new InspectionProfileImpl("allEnabled");
profile.enableAllTools(project);
@@ -186,7 +187,7 @@ public class MadTestingUtil {
manager.addProfile(profile);
InspectionProfileImpl prev = manager.getCurrentProfile();
manager.setCurrentProfile(profile);
Disposer.register(disposable, () -> {
Disposer.register(((ProjectImpl)project).getEarlyDisposable(), () -> {
InspectionProfileImpl.INIT_INSPECTIONS = false;
manager.setCurrentProfile(prev);
manager.deleteProfile(profile);
@@ -549,7 +550,7 @@ public class MadTestingUtil {
Arrays.sort(children, Comparator.comparing(File::getName));
while (true) {
int[] weights = Arrays.stream(children).mapToInt(child -> estimateWeight(child, exhausted)).toArray();
int index = 0;
int index;
try {
index = spin(data, weights);
}
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.lang.properties.propertyBased;
import com.intellij.lang.properties.PropertiesFileType;
@@ -16,7 +16,6 @@ import java.util.function.Supplier;
@SkipSlowTestLocally
public class PropertiesCodeInsightSanityTest extends LightJavaCodeInsightFixtureTestCase {
public void testIncrementalHighlighterUpdate() {
PropertyChecker.checkScenarios(actionsOnPropertiesFiles(CheckHighlighterConsistency.randomEditsWithHighlighterChecks));
}
@@ -26,7 +25,7 @@ public class PropertiesCodeInsightSanityTest extends LightJavaCodeInsightFixture
}
public void testRandomActivity() {
MadTestingUtil.enableAllInspections(getProject(), getTestRootDisposable());
MadTestingUtil.enableAllInspections(getProject());
Function<PsiFile, Generator<? extends MadTestingAction>> fileActions =
file -> Generator.sampledFrom(new InvokeIntention(file, new IntentionPolicy() {
@Override
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.python.propertyBased;
import com.intellij.openapi.application.ApplicationManager;
@@ -40,7 +26,6 @@ import java.util.function.Supplier;
*/
@SkipSlowTestLocally
public class PythonCodeInsightSanityTest extends PyEnvTestCase {
/**
* When this test fail please record its rechecking seed and create stable test providing it to {@link #runActivity(Pair)}
*/
@@ -84,7 +69,7 @@ public class PythonCodeInsightSanityTest extends PyEnvTestCase {
private void runActivity(@Nullable final Pair<Long, Integer> seedToRepeat) {
runSanityTest(pathAndFixture -> {
final CodeInsightTestFixture fixture = pathAndFixture.second;
MadTestingUtil.enableAllInspections(fixture.getProject(), fixture.getProject());
MadTestingUtil.enableAllInspections(fixture.getProject());
Function<PsiFile, Generator<? extends MadTestingAction>> fileActions =
file -> Generator.sampledFrom(new InvokeIntention(file, new IntentionPolicy()),
new InvokeCompletion(file, new CompletionPolicy()),