mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Enforce virtual file pointers leak tracking in fixtures;
moved tracking code away from VFPMI to VirtualFilePointerTracker because it's test-only warn about not paired storePointers()/assertPointersAreDisposed() (memleaks otherwise from myStoredPointers) (disable pointer leak tracking in FixtureRule.kt for now because only @develar knows what's going on there)
This commit is contained in:
@@ -19,8 +19,6 @@ import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.module.StdModuleTypes;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.impl.JavaPsiFacadeEx;
|
||||
@@ -39,16 +37,12 @@ public abstract class IdeaTestCase extends PlatformTestCase {
|
||||
super.setUp();
|
||||
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_6);
|
||||
myJavaFacade = JavaPsiFacadeEx.getInstanceEx(myProject);
|
||||
VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
|
||||
filePointerManager.storePointers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
myJavaFacade = null;
|
||||
super.tearDown();
|
||||
VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
|
||||
filePointerManager.assertPointersAreDisposed();
|
||||
}
|
||||
|
||||
public final JavaPsiFacadeEx getJavaFacade() {
|
||||
|
||||
+2
-27
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.vfs.impl;
|
||||
|
||||
import com.intellij.concurrency.ConcurrentCollectionFactory;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -35,7 +36,6 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerListener;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.concurrency.ConcurrentCollectionFactory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
@@ -312,33 +312,8 @@ public class VirtualFilePointerManagerImpl extends VirtualFilePointerManager imp
|
||||
}
|
||||
}
|
||||
|
||||
private final Set<VirtualFilePointerImpl> myStoredPointers = ContainerUtil.newIdentityTroveSet();
|
||||
|
||||
@TestOnly
|
||||
public synchronized void storePointers() {
|
||||
myStoredPointers.clear();
|
||||
addAllPointersTo(myStoredPointers);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public synchronized void assertPointersAreDisposed() {
|
||||
List<VirtualFilePointerImpl> pointers = new ArrayList<>();
|
||||
addAllPointersTo(pointers);
|
||||
try {
|
||||
for (VirtualFilePointerImpl pointer : pointers) {
|
||||
if (!myStoredPointers.contains(pointer)) {
|
||||
pointer.throwDisposalError("Virtual pointer '" + pointer +
|
||||
"' hasn't been disposed: "+pointer.getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myStoredPointers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
private void addAllPointersTo(@NotNull Collection<VirtualFilePointerImpl> pointers) {
|
||||
synchronized void addAllPointersTo(@NotNull Collection<VirtualFilePointerImpl> pointers) {
|
||||
List<FilePointerPartNode> out = new ArrayList<>();
|
||||
for (FilePointerPartNode root : myPointers.values()) {
|
||||
root.addPointersUnder(null, false, "", out);
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.openapi.vfs.impl;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Tracks leaks of file pointers from {@link VirtualFilePointerManagerImpl}
|
||||
* Usage:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyTest {
|
||||
* VirtualFilePointerTracker myTracker;
|
||||
* void setUpOrSomewhereBeforeTestExecution() {
|
||||
* myTracker = new VirtualFilePointerTracker(); // all virtual file pointers created by this moment are remembered
|
||||
* }
|
||||
* void tearDownOrSomewhereAfterTestExecuted() {
|
||||
* myTracker.assertPointersAreDisposed(); // throws if there are virtual file pointers created after setup but never disposed
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
@TestOnly
|
||||
public class VirtualFilePointerTracker {
|
||||
private static final Set<VirtualFilePointerImpl> storedPointers = ContainerUtil.newIdentityTroveSet();
|
||||
private static Throwable trace;
|
||||
private static boolean isTracking; // true when storePointers() was called but before assertPointersDisposed(). false otherwise
|
||||
|
||||
public VirtualFilePointerTracker() {
|
||||
storePointers();
|
||||
}
|
||||
|
||||
private synchronized void storePointers() {
|
||||
if (isTracking) {
|
||||
throw new IllegalStateException("Previous test did not call assertPointersAreDisposed() - see 'Caused by:' for its stacktrace", trace);
|
||||
}
|
||||
trace = new Throwable();
|
||||
storedPointers.clear();
|
||||
addAllPointersTo(storedPointers);
|
||||
//System.out.println("VFPT.storePointers(" + storedPointers + ")");
|
||||
isTracking = true;
|
||||
}
|
||||
|
||||
public synchronized void assertPointersAreDisposed() {
|
||||
if (!isTracking) {
|
||||
throw new IllegalStateException("Double call of assertPointersAreDisposed() - see 'Caused by:' for the previous call", trace);
|
||||
}
|
||||
List<VirtualFilePointerImpl> pointers = new ArrayList<>();
|
||||
addAllPointersTo(pointers);
|
||||
//System.out.println("VFPT.assertPointersAreDisposed(" +pointers+")");
|
||||
for (int i = pointers.size() - 1; i >= 0; i--) {
|
||||
VirtualFilePointerImpl pointer = pointers.get(i);
|
||||
if (storedPointers.remove(pointer)) {
|
||||
pointers.remove(i);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Set<VirtualFilePointerImpl> leaked = ContainerUtil.newTroveSet(new TObjectHashingStrategy<VirtualFilePointerImpl>() {
|
||||
@Override
|
||||
public int computeHashCode(VirtualFilePointerImpl pointer) {
|
||||
return FileUtil.PATH_HASHING_STRATEGY.computeHashCode(pointer.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(VirtualFilePointerImpl o1, VirtualFilePointerImpl o2) {
|
||||
return FileUtil.PATH_HASHING_STRATEGY.equals(o1.getUrl(), o2.getUrl());
|
||||
}
|
||||
}, pointers);
|
||||
leaked.removeAll(storedPointers);
|
||||
|
||||
for (VirtualFilePointerImpl pointer : leaked) {
|
||||
pointer.throwDisposalError("Virtual pointer '" + pointer +
|
||||
"' hasn't been disposed: " + pointer.getStackTrace());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
storedPointers.clear();
|
||||
trace = new Throwable();
|
||||
isTracking = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAllPointersTo(@NotNull Collection<VirtualFilePointerImpl> pointers) {
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).addAllPointersTo(pointers);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,8 @@ class ProjectRule(val projectDescriptor: LightProjectDescriptor = LightProjectDe
|
||||
}
|
||||
}
|
||||
|
||||
(VirtualFilePointerManager.getInstance() as VirtualFilePointerManagerImpl).storePointers()
|
||||
// TODO uncomment and figure out where to put this statement
|
||||
// (VirtualFilePointerManager.getInstance() as VirtualFilePointerManagerImpl).storePointers()
|
||||
return project
|
||||
}
|
||||
|
||||
@@ -100,7 +101,8 @@ class ProjectRule(val projectDescriptor: LightProjectDescriptor = LightProjectDe
|
||||
sharedProject = null
|
||||
sharedModule = null
|
||||
(ProjectManager.getInstance() as ProjectManagerImpl).forceCloseProject(project, true)
|
||||
(VirtualFilePointerManager.getInstance() as VirtualFilePointerManagerImpl).assertPointersAreDisposed()
|
||||
// TODO uncomment and figure out where to put this statement
|
||||
// (VirtualFilePointerManager.getInstance() as VirtualFilePointerManagerImpl).assertPointersAreDisposed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,10 +71,9 @@ import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManager;
|
||||
import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerTracker;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
@@ -139,6 +138,8 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
|
||||
PlatformTestUtil.registerProjectCleanup(LightPlatformTestCase::closeAndDeleteProject);
|
||||
}
|
||||
|
||||
private VirtualFilePointerTracker myVirtualFilePointerTracker;
|
||||
|
||||
/**
|
||||
* @return Project to be used in tests for example for project components retrieval.
|
||||
*/
|
||||
@@ -251,9 +252,6 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
|
||||
ourSourceRoot = sourceRoot;
|
||||
}
|
||||
});
|
||||
|
||||
// project creation may make a lot of pointers, do not regard them as leak
|
||||
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).storePointers();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,8 +280,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
|
||||
|
||||
myThreadTracker = new ThreadTracker();
|
||||
ModuleRootManager.getInstance(ourModule).orderEntries().getAllLibrariesAndSdkClassesRoots();
|
||||
VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
|
||||
filePointerManager.storePointers();
|
||||
myVirtualFilePointerTracker = new VirtualFilePointerTracker();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -390,7 +387,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
|
||||
super::tearDown,
|
||||
() -> myThreadTracker.checkLeak(),
|
||||
() -> InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project),
|
||||
() -> ((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).assertPointersAreDisposed()
|
||||
() -> myVirtualFilePointerTracker.assertPointersAreDisposed()
|
||||
).run();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,11 +58,14 @@ import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerTracker;
|
||||
import com.intellij.openapi.vfs.impl.jar.JarFileSystemImpl;
|
||||
import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
|
||||
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
@@ -125,6 +128,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
private static boolean ourPlatformPrefixInitialized;
|
||||
private static Set<VirtualFile> ourEternallyLivingFilesCache;
|
||||
private Sdk[] myOldSdks;
|
||||
private VirtualFilePointerTracker myVirtualFilePointerTracker;
|
||||
|
||||
/**
|
||||
* If a temp directory is reused from some previous test run, there might be cached children in its VFS.
|
||||
@@ -224,6 +228,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
|
||||
DocumentCommitThread.getInstance().clearQueue();
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
myVirtualFilePointerTracker = new VirtualFilePointerTracker();
|
||||
}
|
||||
|
||||
public final Project getProject() {
|
||||
@@ -518,6 +523,7 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
|
||||
})
|
||||
.append(LightPlatformTestCase::checkEditorsReleased)
|
||||
.append(() -> UsefulTestCase.checkForJdkTableLeaks(myOldSdks))
|
||||
.append(() -> myVirtualFilePointerTracker.assertPointersAreDisposed())
|
||||
.append(() -> {
|
||||
myProjectManager = null;
|
||||
myProject = null;
|
||||
|
||||
+14
@@ -83,18 +83,22 @@ import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.extensions.ExtensionsArea;
|
||||
import com.intellij.openapi.fileEditor.*;
|
||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
|
||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.impl.VirtualFilePointerTracker;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.psi.impl.PsiManagerEx;
|
||||
@@ -162,6 +166,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
private ChooseByNameBase myChooseByNamePopup;
|
||||
private boolean myAllowDirt;
|
||||
private boolean myCaresAboutInjection = true;
|
||||
private VirtualFilePointerTracker myVirtualFilePointerTracker;
|
||||
|
||||
public CodeInsightTestFixtureImpl(@NotNull IdeaProjectTestFixture projectFixture, @NotNull TempDirTestFixture tempDirTestFixture) {
|
||||
myProjectFixture = projectFixture;
|
||||
@@ -1206,6 +1211,11 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
ensureIndexesUpToDate(getProject());
|
||||
((StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject())).runPostStartupActivities();
|
||||
});
|
||||
|
||||
for (Module module : ModuleManager.getInstance(getProject()).getModules()) {
|
||||
ModuleRootManager.getInstance(module).orderEntries().getAllLibrariesAndSdkClassesRoots(); // instantiate all VFPs
|
||||
}
|
||||
myVirtualFilePointerTracker = new VirtualFilePointerTracker();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1233,12 +1243,16 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
myVirtualFilePointerTracker.assertPointersAreDisposed();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeOpenFiles() {
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
|
||||
for (VirtualFile file : EditorHistoryManager.getInstance(getProject()).getFiles()) {
|
||||
EditorHistoryManager.getInstance(getProject()).removeFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user