Add a mechanism to track disposables from unit tests

This commit is contained in:
Alexandru Dima 2021-01-11 08:27:07 +01:00
parent 11ac71b272
commit 7c3aacb40a
No known key found for this signature in database
GPG key ID: 6E58D7B045760DA0
2 changed files with 78 additions and 23 deletions

View file

@ -14,34 +14,53 @@ import { Iterable } from 'vs/base/common/iterator';
* extend Disposable or use a DisposableStore. This means there are a lot of false positives.
*/
const TRACK_DISPOSABLES = false;
let disposableTracker: IDisposableTracker | null = null;
const __is_disposable_tracked__ = '__is_disposable_tracked__';
function markTracked<T extends IDisposable>(x: T): void {
if (!TRACK_DISPOSABLES) {
return;
}
if (x && x !== Disposable.None) {
try {
(x as any)[__is_disposable_tracked__] = true;
} catch {
// noop
}
}
export interface IDisposableTracker {
trackDisposable(x: IDisposable): void;
markTracked(x: IDisposable): void;
}
function trackDisposable<T extends IDisposable>(x: T): T {
if (!TRACK_DISPOSABLES) {
export function setDisposableTracker(tracker: IDisposableTracker | null): void {
disposableTracker = tracker;
}
if (TRACK_DISPOSABLES) {
const __is_disposable_tracked__ = '__is_disposable_tracked__';
disposableTracker = new class implements IDisposableTracker {
trackDisposable(x: IDisposable): void {
const stack = new Error('Potentially leaked disposable').stack!;
setTimeout(() => {
if (!(x as any)[__is_disposable_tracked__]) {
console.log(stack);
}
}, 3000);
}
markTracked(x: IDisposable): void {
if (x && x !== Disposable.None) {
try {
(x as any)[__is_disposable_tracked__] = true;
} catch {
// noop
}
}
}
};
}
function markTracked<T extends IDisposable>(x: T): void {
if (!disposableTracker) {
return;
}
disposableTracker.markTracked(x);
}
export function trackDisposable<T extends IDisposable>(x: T): T {
if (!disposableTracker) {
return x;
}
const stack = new Error('Potentially leaked disposable').stack!;
setTimeout(() => {
if (!(x as any)[__is_disposable_tracked__]) {
console.log(stack);
}
}, 3000);
disposableTracker.trackDisposable(x);
return x;
}

View file

@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, IDisposableTracker, setDisposableTracker } from 'vs/base/common/lifecycle';
class DisposableTracker implements IDisposableTracker {
allDisposables: [IDisposable, string][] = [];
trackDisposable(x: IDisposable): void {
this.allDisposables.push([x, new Error().stack!]);
}
markTracked(x: IDisposable): void {
for (let idx = 0; idx < this.allDisposables.length; idx++) {
if (this.allDisposables[idx][0] === x) {
this.allDisposables.splice(idx, 1);
return;
}
}
}
}
let currentTracker: DisposableTracker | null = null;
export function beginTrackingDisposables(): void {
currentTracker = new DisposableTracker();
setDisposableTracker(currentTracker);
}
export function logTrackedDisposables(): void {
if (currentTracker) {
setDisposableTracker(null);
console.log(currentTracker!.allDisposables.map(e => `${e[0]}\n${e[1]}`).join('\n\n'));
currentTracker = null;
}
}