update theOnlyProject field after project dispose because otherwise "projectDisposed" listeners from the other project might get the wrong project to fix IDEA-209724 Smart pointer creation during project disposal leads to "Element from alien project" assertion

This commit is contained in:
Alexey Kudravtsev
2019-04-01 13:50:18 +03:00
parent 4ca861ad28
commit e2520e973f
4 changed files with 18 additions and 14 deletions
@@ -3,7 +3,6 @@ package com.intellij.openapi.project.impl;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.ProjectManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,6 +50,5 @@ final class DefaultProject extends ProjectImpl {
if (LOG.isDebugEnabled()) {
LOG.debug("Disposed DefaultProject "+this);
}
((ProjectManagerImpl)ProjectManager.getInstance()).updateTheOnlyProjectField();
}
}
@@ -40,7 +40,7 @@ public class DefaultProjectTimed extends TimedReference<Project> {
@NotNull
@Override
public synchronized Project get() {
public Project get() {
Project value = super.get();
if (value == null) {
value = compute();
@@ -50,7 +50,7 @@ public class DefaultProjectTimed extends TimedReference<Project> {
}
@Override
public synchronized void dispose() {
public void dispose() {
// project must be disposed in EDT in write action
Runnable doDispose = () -> WriteCommandAction.runWriteCommandAction(null, () -> super.dispose());
if (ApplicationManager.getApplication().isDispatchThread()) {
@@ -29,6 +29,7 @@ import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.startup.StartupManager;
@@ -347,6 +348,8 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
if (!application.isDisposed()) {
application.getMessageBus().syncPublisher(ProjectLifecycleListener.TOPIC).afterProjectClosed(this);
}
((ProjectManagerImpl)ProjectManager.getInstance()).updateTheOnlyProjectField();
TimedReference.disposeTimed();
LaterInvocator.purgeExpiredItems();
}
@@ -328,19 +328,23 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
@Override
@TestOnly
public synchronized boolean isDefaultProjectInitialized() {
return myDefaultProjectTimed.isCached();
public boolean isDefaultProjectInitialized() {
synchronized (lock) {
return myDefaultProjectTimed.isCached();
}
}
@Override
@NotNull
public synchronized Project getDefaultProject() {
LOG.assertTrue(!ApplicationManager.getApplication().isDisposed(), "Default project has been already disposed!");
Project defaultProject = myDefaultProjectTimed.get();
// disable "the only project" optimization since we have now more than one project.
// (even though the default project is not a real project, it can be used indirectly in e.g. "Settings|Code Style" code fragments PSI)
updateTheOnlyProjectField();
return defaultProject;
public Project getDefaultProject() {
synchronized (lock) {
LOG.assertTrue(!ApplicationManager.getApplication().isDisposed(), "Default project has been already disposed!");
Project defaultProject = myDefaultProjectTimed.get();
// disable "the only project" optimization since we have now more than one project.
// (even though the default project is not a real project, it can be used indirectly in e.g. "Settings|Code Style" code fragments PSI)
updateTheOnlyProjectField();
return defaultProject;
}
}
@Override
@@ -459,7 +463,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
private void removeFromOpened(@NotNull Project project) {
synchronized (lock) {
myOpenProjects = ArrayUtil.remove(myOpenProjects, project);
updateTheOnlyProjectField();
myOpenProjectByHash.values().remove(project); // remove by value and not by key!
}
}