Add eslint rule for potentially unsafe disposable patterns (#209555)

`DisposableStore`/`MutableDisposable` properties should almost always be `readonly`. Otherwise it's easy to accidentally overwrite the property and leak the previous value. This commonly happens with code such as:

```ts
class Foo {
     private disposables = new DisposableStore();

     bar() {
         this.disposables = new DisposableStore(); // leaks old values
         ...
     }
```

This change adds an eslint rule to enforce this and adopts `readonly` for the caught cases. I only needed to add 2 suppression comments, which seems like an acceptable tradeoff for helping catch a common mistake
This commit is contained in:
Matt Bierner 2024-04-04 10:34:45 -07:00 committed by GitHub
parent b4378dfa1d
commit ae91138701
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 151 additions and 111 deletions

View File

@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
/**
* Checks for potentially unsafe usage of `DisposableStore` / `MutableDisposable`.
*
* These have been the source of leaks in the past.
*/
export = new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkVariableDeclaration(inNode: any) {
context.report({
node: inNode,
message: `Use const for 'DisposableStore' to avoid leaks by accidental reassignment.`
});
}
function checkProperty(inNode: any) {
context.report({
node: inNode,
message: `Use readonly for DisposableStore/MutableDisposable to avoid leaks through accidental reassignment.`
});
}
return {
'VariableDeclaration[kind!="const"] NewExpression[callee.name="DisposableStore"]': checkVariableDeclaration,
'PropertyDefinition[readonly!=true][typeAnnotation.typeAnnotation.typeName.name=/DisposableStore|MutableDisposable/]': checkProperty,
'PropertyDefinition[readonly!=true] NewExpression[callee.name=/DisposableStore|MutableDisposable/]': checkProperty,
};
}
};

View File

@ -72,6 +72,7 @@
"local/code-no-native-private": "warn",
"local/code-parameter-properties-must-have-explicit-accessibility": "warn",
"local/code-no-nls-in-standalone-editor": "warn",
"local/code-no-potentially-unsafe-disposables": "warn",
"local/code-no-standalone-editor": "warn",
"local/code-no-unexternalized-strings": "warn",
"local/code-must-use-super-dispose": "warn",

View File

@ -51,7 +51,7 @@ export class FindInput extends Widget {
private readonly showCommonFindToggles: boolean;
private fixFocusOnOptionClickEnabled = true;
private imeSessionInProgress = false;
private additionalTogglesDisposables: MutableDisposable<DisposableStore> = this._register(new MutableDisposable());
private readonly additionalTogglesDisposables: MutableDisposable<DisposableStore> = this._register(new MutableDisposable());
protected readonly controls: HTMLDivElement;
protected readonly regex?: RegexToggle;

View File

@ -55,7 +55,7 @@ export class ToolBar extends Disposable {
private _onDidChangeDropdownVisibility = this._register(new EventMultiplexer<boolean>());
readonly onDidChangeDropdownVisibility = this._onDidChangeDropdownVisibility.event;
private disposables = this._register(new DisposableStore());
private readonly disposables = this._register(new DisposableStore());
constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {
super();

View File

@ -64,7 +64,7 @@ class TreeNodeListDragAndDrop<T, TFilterData, TRef> implements IListDragAndDrop<
private autoExpandNode: ITreeNode<T, TFilterData> | undefined;
private autoExpandDisposable: IDisposable = Disposable.None;
private disposables = new DisposableStore();
private readonly disposables = new DisposableStore();
constructor(private modelProvider: () => ITreeModel<T, TFilterData, TRef>, private dnd: ITreeDragAndDrop<T>) { }
@ -1561,7 +1561,7 @@ class StickyScrollWidget<T, TFilterData, TRef> implements IDisposable {
private readonly _rootDomNode: HTMLElement;
private _previousState: StickyScrollState<T, TFilterData, TRef> | undefined;
private _previousElements: HTMLElement[] = [];
private _previousStateDisposables: DisposableStore = new DisposableStore();
private readonly _previousStateDisposables: DisposableStore = new DisposableStore();
private stickyScrollFocus: StickyScrollFocus<T, TFilterData, TRef>;
readonly onDidChangeHasFocus: Event<boolean>;

View File

@ -561,7 +561,7 @@ export class MutableDisposable<T extends IDisposable> implements IDisposable {
* exist and cannot be undefined.
*/
export class MandatoryMutableDisposable<T extends IDisposable> implements IDisposable {
private _disposable = new MutableDisposable<T>();
private readonly _disposable = new MutableDisposable<T>();
private _isDisposed = false;
constructor(initialValue: T) {

View File

@ -827,6 +827,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
private _socket: ISocket;
private _socketWriter: ProtocolWriter;
private _socketReader: ProtocolReader;
// eslint-disable-next-line local/code-no-potentially-unsafe-disposables
private _socketDisposables: DisposableStore;
private readonly _loadEstimator: ILoadEstimator;

View File

@ -196,7 +196,7 @@ export class TextAreaInput extends Disposable {
private readonly _asyncTriggerCut: RunOnceScheduler;
private _asyncFocusGainWriteScreenReaderContent: MutableDisposable<RunOnceScheduler> = this._register(new MutableDisposable());
private readonly _asyncFocusGainWriteScreenReaderContent: MutableDisposable<RunOnceScheduler> = this._register(new MutableDisposable());
private _textAreaState: TextAreaState;

View File

@ -359,7 +359,7 @@ export interface CssProperties {
class RefCountedCssRule {
private _referenceCount: number = 0;
private _styleElement: HTMLStyleElement | undefined;
private _styleElementDisposables: DisposableStore;
private readonly _styleElementDisposables: DisposableStore;
constructor(
public readonly key: string,

View File

@ -245,7 +245,7 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati
private _buffer: model.ITextBuffer;
private _bufferDisposable: IDisposable;
private _options: model.TextModelResolvedOptions;
private _languageSelectionListener = this._register(new MutableDisposable<IDisposable>());
private readonly _languageSelectionListener = this._register(new MutableDisposable<IDisposable>());
private _isDisposed: boolean;
private __isDisposing: boolean;

View File

@ -195,7 +195,7 @@ export class ColorDetector extends Disposable implements IEditorContribution {
});
}
private _colorDecorationClassRefs = this._register(new DisposableStore());
private readonly _colorDecorationClassRefs = this._register(new DisposableStore());
private updateColorDecorators(colorData: IColorData[]): void {
this._colorDecorationClassRefs.clear();

View File

@ -569,7 +569,7 @@ class RenameCandidateListView {
private _minimumWidth: number;
private _typicalHalfwidthCharacterWidth: number;
private _disposables: DisposableStore;
private readonly _disposables: DisposableStore;
// FIXME@ulugbekna: rewrite using event emitters
constructor(parent: HTMLElement, opts: { fontInfo: FontInfo; onFocusChange: (newSymbolName: string) => void; onSelectionChange: () => void }) {
@ -788,7 +788,7 @@ class RenameInput implements IDisposable {
private readonly _onDidChange = new Emitter<void>();
public readonly onDidChange = this._onDidChange.event;
private _disposables = new DisposableStore();
private readonly _disposables = new DisposableStore();
get domNode() {
if (!this._domNode) {

View File

@ -12,7 +12,7 @@ import { getWindow } from 'vs/base/browser/dom';
export class ContextViewHandler extends Disposable implements IContextViewProvider {
private currentViewDisposable = this._register(new MutableDisposable<IDisposable>());
private readonly currentViewDisposable = this._register(new MutableDisposable<IDisposable>());
protected readonly contextView = this._register(new ContextView(this.layoutService.mainContainer, ContextViewDOMPosition.ABSOLUTE));
constructor(

View File

@ -30,7 +30,7 @@ export class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate
return this._delay;
}
private hoverDisposables = this._register(new DisposableStore());
private readonly hoverDisposables = this._register(new DisposableStore());
constructor(
public readonly placement: 'mouse' | 'element',

View File

@ -13,7 +13,7 @@ import { ILogService } from 'vs/platform/log/common/log';
export class NativePolicyService extends AbstractPolicyService implements IPolicyService {
private throttler = new Throttler();
private watcher = this._register(new MutableDisposable<Watcher>());
private readonly watcher = this._register(new MutableDisposable<Watcher>());
constructor(
@ILogService private readonly logService: ILogService,

View File

@ -707,7 +707,7 @@ export class QuickInputTree extends Disposable {
private _elementTree = new Array<IQuickPickElement>();
private _itemElements = new Array<QuickPickItemElement>();
// Elements that apply to the current set of elements
private _elementDisposable = this._register(new DisposableStore());
private readonly _elementDisposable = this._register(new DisposableStore());
private _lastHover: IHoverWidget | undefined;
// This is used to prevent setting the checked state of a single element from firing the checked events
// so that we can batch them together. This can probably be improved by handling events differently,

View File

@ -35,7 +35,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
private _commitCommandFinished?: RunOnceScheduler;
private _ptyHeuristicsHooks: ICommandDetectionHeuristicsHooks;
private _ptyHeuristics: MandatoryMutableDisposable<IPtyHeuristics>;
private readonly _ptyHeuristics: MandatoryMutableDisposable<IPtyHeuristics>;
get commands(): readonly TerminalCommand[] { return this._commands; }
get executingCommand(): string | undefined { return this._currentCommand.command; }
@ -514,7 +514,7 @@ const enum AdjustCommandStartMarkerConstants {
*/
class WindowsPtyHeuristics extends Disposable {
private _onCursorMoveListener = this._register(new MutableDisposable());
private readonly _onCursorMoveListener = this._register(new MutableDisposable());
private _tryAdjustCommandStartMarkerScheduler?: RunOnceScheduler;
private _tryAdjustCommandStartMarkerScannedLineCount: number = 0;

View File

@ -49,7 +49,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
* provided through this, even from multiple ext link providers. Xterm should remove lower
* priority intersecting links itself.
*/
private _linkProvider = this._store.add(new MutableDisposable());
private readonly _linkProvider = this._store.add(new MutableDisposable());
private _os: OperatingSystem = OS;

View File

@ -397,7 +397,7 @@ export function createExtHostComments(mainContext: IMainContext, commands: ExtHo
private _commentsMap: Map<vscode.Comment, number> = new Map<vscode.Comment, number>();
private _acceptInputDisposables = new MutableDisposable<DisposableStore>();
private readonly _acceptInputDisposables = new MutableDisposable<DisposableStore>();
readonly value: vscode.CommentThread2;

View File

@ -559,7 +559,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
}
private _historyProvider: vscode.SourceControlHistoryProvider | undefined;
private _historyProviderDisposable = new MutableDisposable<DisposableStore>();
private readonly _historyProviderDisposable = new MutableDisposable<DisposableStore>();
private _historyProviderCurrentHistoryItemGroup: vscode.SourceControlHistoryItemGroup | undefined;
get historyProvider(): vscode.SourceControlHistoryProvider | undefined {
@ -598,7 +598,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
this.#proxy.$updateSourceControl(this.handle, { commitTemplate });
}
private _acceptInputDisposables = new MutableDisposable<DisposableStore>();
private readonly _acceptInputDisposables = new MutableDisposable<DisposableStore>();
private _acceptInputCommand: vscode.Command | undefined = undefined;
get acceptInputCommand(): vscode.Command | undefined {
@ -614,7 +614,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
this.#proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal });
}
private _actionButtonDisposables = new MutableDisposable<DisposableStore>();
private readonly _actionButtonDisposables = new MutableDisposable<DisposableStore>();
private _actionButton: vscode.SourceControlActionButton | undefined;
get actionButton(): vscode.SourceControlActionButton | undefined {
checkProposedApiEnabled(this._extension, 'scmActionButton');
@ -639,7 +639,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
}
private _statusBarDisposables = new MutableDisposable<DisposableStore>();
private readonly _statusBarDisposables = new MutableDisposable<DisposableStore>();
private _statusBarCommands: vscode.Command[] | undefined = undefined;
get statusBarCommands(): vscode.Command[] | undefined {

View File

@ -46,6 +46,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private _name?: string;
private _color?: string | ThemeColor;
private _backgroundColor?: ThemeColor;
// eslint-disable-next-line local/code-no-potentially-unsafe-disposables
private _latestCommandRegistration?: DisposableStore;
private readonly _staleCommandRegistrations = new DisposableStore();
private _command?: {

View File

@ -393,7 +393,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
protected _environmentVariableCollections: Map<string, UnifiedEnvironmentVariableCollection> = new Map();
private _defaultProfile: ITerminalProfile | undefined;
private _defaultAutomationProfile: ITerminalProfile | undefined;
private _lastQuickFixCommands: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private readonly _lastQuickFixCommands: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private readonly _bufferer: TerminalDataBufferer;
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();

View File

@ -23,7 +23,7 @@ class MenuActions extends Disposable {
private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange = this._onDidChange.event;
private disposables = this._register(new DisposableStore());
private readonly disposables = this._register(new DisposableStore());
constructor(
menuId: MenuId,

View File

@ -291,7 +291,7 @@ class ResourceLabelWidget extends IconLabel {
readonly onDidRender = this._onDidRender.event;
private label: IResourceLabelProps | undefined = undefined;
private decoration = this._register(new MutableDisposable<IDecoration>());
private readonly decoration = this._register(new MutableDisposable<IDecoration>());
private options: IResourceLabelOptions | undefined = undefined;
private computedIconClasses: string[] | undefined = undefined;

View File

@ -29,7 +29,7 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution
// Auto save: focus change & window change
private lastActiveEditor: EditorInput | undefined = undefined;
private lastActiveGroupId: GroupIdentifier | undefined = undefined;
private lastActiveEditorControlDisposable = this._register(new DisposableStore());
private readonly lastActiveEditorControlDisposable = this._register(new DisposableStore());
// Auto save: waiting on specific condition
private readonly waitingOnConditionAutoSaveWorkingCopies = new ResourceMap<{ readonly workingCopy: IWorkingCopy; readonly reason: SaveReason; condition: AutoSaveDisabledReason }>(resource => this.uriIdentityService.extUri.getComparisonKey(resource));

View File

@ -52,7 +52,7 @@ export abstract class EditorPlaceholder extends EditorPane {
private container: HTMLElement | undefined;
private scrollbar: DomScrollableElement | undefined;
private inputDisposable = this._register(new MutableDisposable());
private readonly inputDisposable = this._register(new MutableDisposable());
constructor(
id: string,

View File

@ -36,10 +36,10 @@ export interface IEditorTitleControlDimensions {
export class EditorTitleControl extends Themable {
private editorTabsControl: IEditorTabsControl;
private editorTabsControlDisposable = this._register(new DisposableStore());
private readonly editorTabsControlDisposable = this._register(new DisposableStore());
private breadcrumbsControlFactory: BreadcrumbsControlFactory | undefined;
private breadcrumbsControlDisposables = this._register(new DisposableStore());
private readonly breadcrumbsControlDisposables = this._register(new DisposableStore());
private get breadcrumbsControl() { return this.breadcrumbsControlFactory?.control; }
constructor(

View File

@ -116,9 +116,9 @@ export abstract class AbstractPaneCompositePart extends CompositePart<PaneCompos
private readonly location: ViewContainerLocation;
private titleContainer: HTMLElement | undefined;
private headerFooterCompositeBarContainer: HTMLElement | undefined;
protected headerFooterCompositeBarDispoables = this._register(new DisposableStore());
protected readonly headerFooterCompositeBarDispoables = this._register(new DisposableStore());
private paneCompositeBarContainer: HTMLElement | undefined;
private paneCompositeBar = this._register(new MutableDisposable<PaneCompositeBar>());
private readonly paneCompositeBar = this._register(new MutableDisposable<PaneCompositeBar>());
private compositeBarPosition: CompositeBarPosition | undefined = undefined;
private emptyPaneMessageElement: HTMLElement | undefined;

View File

@ -143,7 +143,7 @@ export abstract class MenubarControl extends Disposable {
protected topLevelTitles: { [menu: string]: string } = {};
protected mainMenuDisposables: DisposableStore;
protected readonly mainMenuDisposables: DisposableStore;
protected recentlyOpened: IRecentlyOpened = { files: [], workspaces: [] };
@ -564,7 +564,7 @@ export class CustomMenubarControl extends MenubarControl {
return result;
}
private reinstallDisposables = this._register(new DisposableStore());
private readonly reinstallDisposables = this._register(new DisposableStore());
private setupCustomMenubar(firstTime: boolean): void {
// If there is no container, we cannot setup the menubar
if (!this.container) {

View File

@ -235,8 +235,8 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart {
private lastLayoutDimensions: Dimension | undefined;
private actionToolBar!: WorkbenchToolBar;
private actionToolBarDisposable = this._register(new DisposableStore());
private editorActionsChangeDisposable = this._register(new DisposableStore());
private readonly actionToolBarDisposable = this._register(new DisposableStore());
private readonly editorActionsChangeDisposable = this._register(new DisposableStore());
private actionToolBarElement!: HTMLElement;
private layoutToolbarMenu: IMenu | undefined;

View File

@ -48,7 +48,7 @@ class EntitlementsContribution extends Disposable implements IWorkbenchContribut
private isInitialized = false;
private showAccountsBadgeContextKey = new RawContextKey<boolean>(accountsBadgeConfigKey, false).bindTo(this.contextService);
private showChatWelcomeViewContextKey = new RawContextKey<boolean>(chatWelcomeViewConfigKey, false).bindTo(this.contextService);
private accountsMenuBadgeDisposable = this._register(new MutableDisposable());
private readonly accountsMenuBadgeDisposable = this._register(new MutableDisposable());
constructor(
@IContextKeyService private readonly contextService: IContextKeyService,

View File

@ -93,7 +93,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
private inputSideToolbarContainer?: HTMLElement;
private followupsContainer!: HTMLElement;
private followupsDisposables = this._register(new DisposableStore());
private readonly followupsDisposables = this._register(new DisposableStore());
private implicitContextContainer!: HTMLElement;
private implicitContextLabel!: HTMLElement;

View File

@ -156,7 +156,7 @@ class QuickChat extends Disposable {
private sash!: Sash;
private model: ChatModel | undefined;
private _currentQuery: string | undefined;
private maintainScrollTimer: MutableDisposable<IDisposable> = this._register(new MutableDisposable<IDisposable>());
private readonly maintainScrollTimer: MutableDisposable<IDisposable> = this._register(new MutableDisposable<IDisposable>());
private _deferUpdatingDynamicLayout: boolean = false;
constructor(

View File

@ -43,7 +43,7 @@ export class ChatViewPane extends ViewPane implements IChatViewPane {
private _widget!: ChatWidget;
get widget(): ChatWidget { return this._widget; }
private modelDisposables = this._register(new DisposableStore());
private readonly modelDisposables = this._register(new DisposableStore());
private memento: Memento;
private readonly viewState: IViewPaneState;
private didProviderRegistrationFail = false;

View File

@ -131,7 +131,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
private previousTreeScrollHeight: number = 0;
private viewModelDisposables = this._register(new DisposableStore());
private readonly viewModelDisposables = this._register(new DisposableStore());
private _viewModel: ChatViewModel | undefined;
private set viewModel(viewModel: ChatViewModel | undefined) {
if (this._viewModel === viewModel) {

View File

@ -128,7 +128,7 @@ export class CodeBlockPart extends Disposable {
private currentCodeBlockData: ICodeBlockData | undefined;
private currentScrollWidth = 0;
private disposableStore = this._register(new DisposableStore());
private readonly disposableStore = this._register(new DisposableStore());
constructor(
private readonly options: ChatEditorOptions,

View File

@ -182,7 +182,7 @@ export class EditorDictation extends Disposable implements IEditorContribution {
private readonly widget = this._register(new DictationWidget(this.editor, this.keybindingService));
private readonly editorDictationInProgress = EDITOR_DICTATION_IN_PROGRESS.bindTo(this.contextKeyService);
private sessionDisposables = this._register(new MutableDisposable());
private readonly sessionDisposables = this._register(new MutableDisposable());
constructor(
private readonly editor: ICodeEditor,

View File

@ -183,7 +183,7 @@ class EmptyTextEditorHintContentWidget implements IContentWidget {
private static readonly ID = 'editor.widget.emptyHint';
private domNode: HTMLElement | undefined;
private toDispose: DisposableStore;
private readonly toDispose: DisposableStore;
private isVisible = false;
private ariaLabel: string = '';

View File

@ -214,10 +214,10 @@ export class DebugEditorContribution implements IDebugEditorContribution {
private exceptionWidget: ExceptionWidget | undefined;
private configurationWidget: FloatingEditorClickWidget | undefined;
private altListener = new MutableDisposable();
private readonly altListener = new MutableDisposable();
private altPressed = false;
private oldDecorations = this.editor.createDecorationsCollection();
private displayedStore = new DisposableStore();
private readonly displayedStore = new DisposableStore();
private editorHoverOptions: IEditorHoverOptions | undefined;
private readonly debounceInfo: IFeatureDebounceInformation;

View File

@ -124,7 +124,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
private readonly pendingEditSessionsContext: IContextKey<boolean>;
private static APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn';
private accountsMenuBadgeDisposable = this._register(new MutableDisposable());
private readonly accountsMenuBadgeDisposable = this._register(new MutableDisposable());
private registeredCommands = new Set<string>();

View File

@ -93,8 +93,8 @@ class RecommendationsNotification extends Disposable {
return this.cancelled;
}
private onDidCloseDisposable = this._register(new MutableDisposable());
private onDidChangeVisibilityDisposable = this._register(new MutableDisposable());
private readonly onDidCloseDisposable = this._register(new MutableDisposable());
private readonly onDidChangeVisibilityDisposable = this._register(new MutableDisposable());
private updateNotificationHandle(notificationHandle: INotificationHandle) {
this.onDidCloseDisposable.clear();
this.onDidChangeVisibilityDisposable.clear();

View File

@ -191,7 +191,7 @@ export class RatingsWidget extends ExtensionWidget {
export class VerifiedPublisherWidget extends ExtensionWidget {
private disposables = this._register(new DisposableStore());
private readonly disposables = this._register(new DisposableStore());
private readonly containerHover: IUpdatableHover;
constructor(
@ -238,7 +238,7 @@ export class VerifiedPublisherWidget extends ExtensionWidget {
export class SponsorWidget extends ExtensionWidget {
private disposables = this._register(new DisposableStore());
private readonly disposables = this._register(new DisposableStore());
constructor(
private container: HTMLElement,

View File

@ -1067,7 +1067,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
private compressedDragOverElement: HTMLElement | undefined;
private compressedDropTargetDisposable: IDisposable = Disposable.None;
private disposables = new DisposableStore();
private readonly disposables = new DisposableStore();
private dropEnabled = false;
constructor(

View File

@ -138,7 +138,7 @@ export class InlineChatWidget {
private _isLayouting: boolean = false;
private _followUpDisposables = this._store.add(new DisposableStore());
private readonly _followUpDisposables = this._store.add(new DisposableStore());
constructor(
location: ChatAgentLocation,
options: IInlineChatWidgetConstructionOptions,

View File

@ -102,12 +102,12 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
private _editorGroupService: IEditorGroupsService;
private _notebookExecutionStateService: INotebookExecutionStateService;
private _extensionService: IExtensionService;
private _widgetDisposableStore: DisposableStore = this._register(new DisposableStore());
private readonly _widgetDisposableStore: DisposableStore = this._register(new DisposableStore());
private _lastLayoutDimensions?: { readonly dimension: DOM.Dimension; readonly position: DOM.IDomPosition };
private _editorOptions: IEditorOptions;
private _notebookOptions: NotebookOptions;
private _editorMemento: IEditorMemento<InteractiveEditorViewState>;
private _groupListener = this._register(new MutableDisposable());
private readonly _groupListener = this._register(new MutableDisposable());
private _runbuttonToolbar: ToolBar | undefined;
private _onDidFocusWidget = this._register(new Emitter<void>());

View File

@ -103,7 +103,7 @@ export class MarkersView extends FilterViewPane implements IMarkersView {
private readonly onVisibleDisposables = this._register(new DisposableStore());
private widget!: IProblemsWidget;
private widgetDisposables = this._register(new DisposableStore());
private readonly widgetDisposables = this._register(new DisposableStore());
private widgetContainer!: HTMLElement;
private widgetIdentityProvider: IIdentityProvider<MarkerElement | MarkerTableItem>;
private widgetAccessibilityProvider: MarkersWidgetAccessibilityProvider;

View File

@ -105,7 +105,7 @@ class ExecutionStateCellStatusBarItem extends Disposable {
private _currentItemIds: string[] = [];
private _showedExecutingStateTime: number | undefined;
private _clearExecutingStateTimer = this._register(new MutableDisposable());
private readonly _clearExecutingStateTimer = this._register(new MutableDisposable());
constructor(
private readonly _notebookViewModel: INotebookViewModel,

View File

@ -14,7 +14,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
class NotebookKernelDetection extends Disposable implements IWorkbenchContribution {
private _detectionMap = new Map<string, IDisposable>();
private _localDisposableStore = this._register(new DisposableStore());
private readonly _localDisposableStore = this._register(new DisposableStore());
constructor(
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,

View File

@ -255,7 +255,7 @@ export class NotebookChatController extends Disposable implements INotebookEdito
private readonly _userEditingDisposables = this._register(new DisposableStore());
private readonly _ctxLastResponseType: IContextKey<undefined | InlineChatResponseType>;
private _widget: NotebookChatWidget | undefined;
private _widgetDisposableStore = this._register(new DisposableStore());
private readonly _widgetDisposableStore = this._register(new DisposableStore());
private _focusTracker: IFocusTracker | undefined;
constructor(
private readonly _notebookEditor: INotebookEditor,

View File

@ -233,15 +233,15 @@ interface IDiffElementLayoutState {
}
abstract class AbstractElementRenderer extends Disposable {
protected _metadataLocalDisposable = this._register(new DisposableStore());
protected _outputLocalDisposable = this._register(new DisposableStore());
protected readonly _metadataLocalDisposable = this._register(new DisposableStore());
protected readonly _outputLocalDisposable = this._register(new DisposableStore());
protected _ignoreMetadata: boolean = false;
protected _ignoreOutputs: boolean = false;
protected _metadataHeaderContainer!: HTMLElement;
protected _metadataHeader!: PropertyHeader;
protected _metadataInfoContainer!: HTMLElement;
protected _metadataEditorContainer?: HTMLElement;
protected _metadataEditorDisposeStore!: DisposableStore;
protected readonly _metadataEditorDisposeStore!: DisposableStore;
protected _metadataEditor?: CodeEditorWidget | DiffEditorWidget;
protected _outputHeaderContainer!: HTMLElement;
@ -255,7 +255,7 @@ abstract class AbstractElementRenderer extends Disposable {
protected _outputEmptyElement?: HTMLElement;
protected _outputLeftView?: OutputContainer;
protected _outputRightView?: OutputContainer;
protected _outputEditorDisposeStore!: DisposableStore;
protected readonly _outputEditorDisposeStore!: DisposableStore;
protected _outputEditor?: CodeEditorWidget | DiffEditorWidget;
protected _outputMetadataEditor?: DiffEditorWidget;

View File

@ -28,7 +28,7 @@ export class NotebookDiffOverviewRuler extends Themable {
private _removeColor: Color | null;
private _removeColorHex: string | null;
private _disposables: DisposableStore;
private readonly _disposables: DisposableStore;
private _renderAnimationFrame: IDisposable | null;
constructor(readonly notebookEditor: INotebookTextDiffEditor, readonly width: number, container: HTMLElement, @IThemeService themeService: IThemeService) {

View File

@ -204,7 +204,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
private _renderedEditors: Map<ICellViewModel, ICodeEditor> = new Map();
private _viewContext: ViewContext;
private _notebookViewModel: NotebookViewModel | undefined;
private _localStore: DisposableStore = this._register(new DisposableStore());
private readonly _localStore: DisposableStore = this._register(new DisposableStore());
private _localCellStateListeners: DisposableStore[] = [];
private _fontInfo: FontInfo | undefined;
private _dimension?: DOM.Dimension;

View File

@ -16,7 +16,7 @@ import { ICellExecutionStateChangedEvent } from 'vs/workbench/contrib/notebook/c
*/
export abstract class CellContentPart extends Disposable {
protected currentCell: ICellViewModel | undefined;
protected cellDisposables = new DisposableStore();
protected readonly cellDisposables = new DisposableStore();
constructor() {
super();
@ -133,9 +133,9 @@ function safeInvokeNoArg<T>(func: () => T): T | null {
}
export class CellPartsCollection extends Disposable {
private _scheduledOverlayRendering = this._register(new MutableDisposable());
private _scheduledOverlayUpdateState = this._register(new MutableDisposable());
private _scheduledOverlayUpdateExecutionState = this._register(new MutableDisposable());
private readonly _scheduledOverlayRendering = this._register(new MutableDisposable());
private readonly _scheduledOverlayUpdateState = this._register(new MutableDisposable());
private readonly _scheduledOverlayUpdateExecutionState = this._register(new MutableDisposable());
constructor(
private readonly targetWindow: Window,

View File

@ -15,7 +15,7 @@ import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/co
const UPDATE_EXECUTION_ORDER_GRACE_PERIOD = 200;
export class CellExecutionPart extends CellContentPart {
private kernelDisposables = this._register(new DisposableStore());
private readonly kernelDisposables = this._register(new DisposableStore());
constructor(
private readonly _notebookEditor: INotebookEditorDelegate,

View File

@ -272,7 +272,7 @@ class CellStatusBarItem extends Disposable {
}
private _currentItem!: INotebookCellStatusBarItem;
private _itemDisposables = this._register(new DisposableStore());
private readonly _itemDisposables = this._register(new DisposableStore());
constructor(
private readonly _context: INotebookCellActionContext,

View File

@ -103,7 +103,7 @@ export abstract class BaseCellViewModel extends Disposable {
private _editorViewStates: editorCommon.ICodeEditorViewState | null = null;
private _editorTransientState: IWordWrapTransientState | null = null;
private _resolvedCellDecorations = new Map<string, INotebookCellDecorationOptions>();
private _textModelRefChangeDisposable = this._register(new MutableDisposable());
private readonly _textModelRefChangeDisposable = this._register(new MutableDisposable());
private readonly _cellDecorationsChanged = this._register(new Emitter<{ added: INotebookCellDecorationOptions[]; removed: INotebookCellDecorationOptions[] }>());
onCellDecorationsChanged: Event<{ added: INotebookCellDecorationOptions[]; removed: INotebookCellDecorationOptions[] }> = this._cellDecorationsChanged.event;

View File

@ -32,7 +32,7 @@ export class BaseCellEditorOptions extends Disposable implements IBaseCellEditor
lineNumbersMinChars: 3
};
private _localDisposableStore = this._register(new DisposableStore());
private readonly _localDisposableStore = this._register(new DisposableStore());
private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
private _value: IEditorOptions;

View File

@ -102,7 +102,7 @@ export interface NotebookViewModelOptions {
}
export class NotebookViewModel extends Disposable implements EditorFoldingStateDelegate, INotebookViewModel {
private _localStore: DisposableStore = this._register(new DisposableStore());
private readonly _localStore = this._register(new DisposableStore());
private _handleToViewCellMapping = new Map<number, CellViewModel>();
get options(): NotebookViewModelOptions { return this._options; }
private readonly _onDidChangeOptions = this._register(new Emitter<void>());

View File

@ -17,7 +17,7 @@ import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/vie
export class ListTopCellToolbar extends Disposable {
private readonly topCellToolbarContainer: HTMLElement;
private topCellToolbar: HTMLElement;
private viewZone: MutableDisposable<DisposableStore> = this._register(new MutableDisposable());
private readonly viewZone: MutableDisposable<DisposableStore> = this._register(new MutableDisposable());
private readonly _modelDisposables = this._register(new DisposableStore());
constructor(
protected readonly notebookEditor: INotebookEditorDelegate,

View File

@ -141,7 +141,7 @@ export class DefineKeybindingWidget extends Widget {
private _keybindingInputWidget: KeybindingsSearchWidget;
private _outputNode: HTMLElement;
private _showExistingKeybindingsNode: HTMLElement;
private _keybindingDisposables = this._register(new DisposableStore());
private readonly _keybindingDisposables = this._register(new DisposableStore());
private _chords: ResolvedKeybinding[] | null = null;
private _isVisible: boolean = false;

View File

@ -31,7 +31,7 @@ const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutError
class DefineKeybindingEditorContribution extends Disposable implements IDefineKeybindingEditorContribution {
private _keybindingDecorationRenderer = this._register(new MutableDisposable<KeybindingEditorDecorationsRenderer>());
private readonly _keybindingDecorationRenderer = this._register(new MutableDisposable<KeybindingEditorDecorationsRenderer>());
private readonly _defineWidget: DefineKeybindingOverlayWidget;

View File

@ -156,7 +156,7 @@ export class SettingsEditor2 extends EditorPane {
// (!) Lots of props that are set once on the first render
private defaultSettingsEditorModel!: Settings2EditorModel;
private modelDisposables: DisposableStore;
private readonly modelDisposables: DisposableStore;
private rootElement!: HTMLElement;
private headerContainer!: HTMLElement;

View File

@ -751,7 +751,7 @@ export class TunnelPanel extends ViewPane {
private panelContainer: HTMLElement | undefined;
private table!: WorkbenchTable<ITunnelItem>;
private tableDisposables: DisposableStore = this._register(new DisposableStore());
private readonly tableDisposables: DisposableStore = this._register(new DisposableStore());
private tunnelTypeContext: IContextKey<TunnelType>;
private tunnelCloseableContext: IContextKey<boolean>;
private tunnelPrivacyContext: IContextKey<TunnelPrivacyId | string | undefined>;

View File

@ -25,7 +25,7 @@ export class SyncScroll extends Disposable implements IWorkbenchContribution {
private readonly syncScrollDispoasbles = this._register(new DisposableStore());
private readonly paneDisposables = new DisposableStore();
private statusBarEntry = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly statusBarEntry = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private isActive: boolean = false;

View File

@ -172,7 +172,7 @@ export class SearchWidget extends Widget {
public contextLinesInput!: InputBox;
private _notebookFilters: NotebookFindFilters;
private _toggleReplaceButtonListener: MutableDisposable<IDisposable>;
private readonly _toggleReplaceButtonListener: MutableDisposable<IDisposable>;
constructor(
container: HTMLElement,

View File

@ -90,7 +90,7 @@ export class SearchEditor extends AbstractTextCodeEditor<SearchEditorViewState>
private showingIncludesExcludes: boolean = false;
private searchOperation: LongRunningOperation;
private searchHistoryDelayer: Delayer<void>;
private messageDisposables: DisposableStore;
private readonly messageDisposables: DisposableStore;
private container: HTMLElement;
private searchModel: SearchModel;
private ongoingOperations: number = 0;

View File

@ -47,7 +47,7 @@ export class TerminalEditor extends EditorPane {
private _cancelContextMenu: boolean = false;
private _disposableStore = this._register(new DisposableStore());
private readonly _disposableStore = this._register(new DisposableStore());
constructor(
group: IEditorGroup,

View File

@ -169,9 +169,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
private _containerReadyBarrier: AutoOpenBarrier;
private _attachBarrier: AutoOpenBarrier;
private _icon: TerminalIcon | undefined;
private _messageTitleDisposable: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private readonly _messageTitleDisposable: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private _widgetManager: TerminalWidgetManager;
private _dndObserver: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private readonly _dndObserver: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
private _lastLayoutDimensions: dom.Dimension | undefined;
private _hasHadInput: boolean;
private _description?: string;

View File

@ -58,7 +58,7 @@ export class TerminalViewPane extends ViewPane {
private readonly _dropdownMenu: IMenu;
private readonly _singleTabMenu: IMenu;
private _viewShowing: IContextKey<boolean>;
private _disposableStore = this._register(new DisposableStore());
private readonly _disposableStore = this._register(new DisposableStore());
constructor(
options: IViewPaneOptions,

View File

@ -41,7 +41,7 @@ export class MarkNavigationAddon extends Disposable implements IMarkTracker, ITe
private _navigationDecorations: IDecoration[] | undefined;
private _activeCommandGuide?: ITerminalCommand;
private _commandGuideDecorations = this._register(new MutableDisposable<DisposableStore>());
private readonly _commandGuideDecorations = this._register(new MutableDisposable<DisposableStore>());
activate(terminal: Terminal): void {
this._terminal = terminal;

View File

@ -66,7 +66,7 @@ export class TerminalAccessibleViewContribution extends Disposable implements IT
private _bufferTracker: BufferContentTracker | undefined;
private _bufferProvider: TerminalAccessibleBufferProvider | undefined;
private _xterm: Pick<IXtermTerminal, 'shellIntegration' | 'getFont'> & { raw: Terminal } | undefined;
private _onDidRunCommand: MutableDisposable<IDisposable> = new MutableDisposable();
private readonly _onDidRunCommand: MutableDisposable<IDisposable> = new MutableDisposable();
constructor(
private readonly _instance: ITerminalInstance,

View File

@ -19,7 +19,7 @@ export interface ITextAreaData {
export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
private _terminal: Terminal | undefined;
private _listeners = this._register(new MutableDisposable<DisposableStore>());
private readonly _listeners = this._register(new MutableDisposable<DisposableStore>());
private _currentCommand: string | undefined;
private _cursorX: number | undefined;

View File

@ -83,7 +83,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr
private _terminalAgentName = 'terminal';
private _terminalAgentId: string | undefined;
private _model: MutableDisposable<ChatModel> = this._register(new MutableDisposable());
private readonly _model: MutableDisposable<ChatModel> = this._register(new MutableDisposable());
constructor(
private readonly _instance: ITerminalInstance,

View File

@ -118,7 +118,7 @@ class DevModeContribution extends Disposable implements ITerminalContribution {
}
private _xterm: IXtermTerminal & { raw: Terminal } | undefined;
private _activeDevModeDisposables = new MutableDisposable();
private readonly _activeDevModeDisposables = new MutableDisposable();
private _currentColor = 0;
constructor(

View File

@ -28,10 +28,10 @@ export class TerminalStickyScrollContribution extends Disposable implements ITer
private _xterm?: IXtermTerminal & { raw: RawXtermTerminal };
private _overlay = this._register(new MutableDisposable<TerminalStickyScrollOverlay>());
private readonly _overlay = this._register(new MutableDisposable<TerminalStickyScrollOverlay>());
private _enableListeners = this._register(new MutableDisposable());
private _disableListeners = this._register(new MutableDisposable());
private readonly _enableListeners = this._register(new MutableDisposable());
private readonly _disableListeners = this._register(new MutableDisposable());
constructor(
private readonly _instance: ITerminalInstance,

View File

@ -48,7 +48,7 @@ export class TerminalStickyScrollOverlay extends Disposable {
private _stickyScrollOverlay?: RawXtermTerminal;
private _serializeAddon?: SerializeAddonType;
private _canvasAddon = this._register(new MutableDisposable<CanvasAddonType>());
private readonly _canvasAddon = this._register(new MutableDisposable<CanvasAddonType>());
private _pendingCanvasAddon?: CancelablePromise<void>;
private _element?: HTMLElement;
@ -56,7 +56,7 @@ export class TerminalStickyScrollOverlay extends Disposable {
private _currentContent?: string;
private _contextMenu: IMenu;
private _refreshListeners = this._register(new MutableDisposable());
private readonly _refreshListeners = this._register(new MutableDisposable());
private _state: OverlayState = OverlayState.Off;
private _isRefreshQueued = false;

View File

@ -28,7 +28,7 @@ class TerminalSuggestContribution extends DisposableStore implements ITerminalCo
return instance.getContribution<TerminalSuggestContribution>(TerminalSuggestContribution.ID);
}
private _addon: MutableDisposable<SuggestAddon> = new MutableDisposable();
private readonly _addon: MutableDisposable<SuggestAddon> = new MutableDisposable();
private _terminalSuggestWidgetContextKeys: IReadableSet<string> = new Set(TerminalContextKeys.suggestWidgetVisible.key);
private _terminalSuggestWidgetVisibleContextKey: IContextKey<boolean>;

View File

@ -33,7 +33,7 @@ class TerminalMouseWheelZoomContribution extends Disposable implements ITerminal
return instance.getContribution<TerminalMouseWheelZoomContribution>(TerminalMouseWheelZoomContribution.ID);
}
private _listener = this._register(new MutableDisposable());
private readonly _listener = this._register(new MutableDisposable());
constructor(
instance: ITerminalInstance | IDetachedTerminalInstance,

View File

@ -87,10 +87,10 @@ const enum LastFocusState {
export class TestingExplorerView extends ViewPane {
public viewModel!: TestingExplorerViewModel;
private filterActionBar = this._register(new MutableDisposable());
private readonly filterActionBar = this._register(new MutableDisposable());
private container!: HTMLElement;
private treeHeader!: HTMLElement;
private discoveryProgress = this._register(new MutableDisposable<UnmanagedProgress>());
private readonly discoveryProgress = this._register(new MutableDisposable<UnmanagedProgress>());
private readonly filter = this._register(new MutableDisposable<TestingExplorerFilter>());
private readonly filterFocusListener = this._register(new MutableDisposable());
private readonly dimensions = { width: 0, height: 0 };
@ -583,7 +583,7 @@ const enum WelcomeExperience {
class TestingExplorerViewModel extends Disposable {
public tree: TestingObjectTree<FuzzyScore>;
private filter: TestsFilter;
public projection = this._register(new MutableDisposable<ITestTreeProjection>());
public readonly projection = this._register(new MutableDisposable<ITestTreeProjection>());
private readonly revealTimeout = new MutableDisposable();
private readonly _viewMode = TestingContextKeys.viewMode.bindTo(this.contextKeyService);

View File

@ -1230,7 +1230,7 @@ const timelinePin = registerIcon('timeline-pin', Codicon.pin, localize('timeline
const timelineUnpin = registerIcon('timeline-unpin', Codicon.pinned, localize('timelineUnpin', 'Icon for the unpin timeline action.'));
class TimelinePaneCommands extends Disposable {
private sourceDisposables: DisposableStore;
private readonly sourceDisposables: DisposableStore;
constructor(
private readonly pane: TimelinePane,

View File

@ -838,7 +838,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
return localize2('resolveConflicts_global', "Show Conflicts ({0})", this.getConflictsCount());
}
private conflictsActionDisposable = this._register(new MutableDisposable());
private readonly conflictsActionDisposable = this._register(new MutableDisposable());
private registerShowConflictsAction(): void {
this.conflictsActionDisposable.value = undefined;
const that = this;

View File

@ -122,10 +122,10 @@ export class GettingStartedPage extends EditorPane {
private editorInput!: GettingStartedInput;
private inProgressScroll = Promise.resolve();
private dispatchListeners: DisposableStore = new DisposableStore();
private stepDisposables: DisposableStore = new DisposableStore();
private detailsPageDisposables: DisposableStore = new DisposableStore();
private mediaDisposables: DisposableStore = new DisposableStore();
private readonly dispatchListeners: DisposableStore = new DisposableStore();
private readonly stepDisposables: DisposableStore = new DisposableStore();
private readonly detailsPageDisposables: DisposableStore = new DisposableStore();
private readonly mediaDisposables: DisposableStore = new DisposableStore();
// Ensure that the these are initialized before use.
// Currently initialized before use in buildCategoriesSlide and scrollToCategory
@ -161,7 +161,7 @@ export class GettingStartedPage extends EditorPane {
private detailsRenderer: GettingStartedDetailsRenderer;
private categoriesSlideDisposables: DisposableStore;
private readonly categoriesSlideDisposables: DisposableStore;
private showFeaturedWalkthrough = true;
constructor(

View File

@ -841,7 +841,7 @@ export class WorkspaceTrustEditor extends EditorPane {
}
private rendering = false;
private rerenderDisposables: DisposableStore = this._register(new DisposableStore());
private readonly rerenderDisposables: DisposableStore = this._register(new DisposableStore());
@debounce(100)
private async render() {
if (this.rendering) {

View File

@ -34,7 +34,7 @@ export class AuthenticationExtensionsService extends Disposable implements IAuth
declare readonly _serviceBrand: undefined;
private _signInRequestItems = new Map<string, SessionRequestInfo>();
private _sessionAccessRequestItems = new Map<string, { [extensionId: string]: { disposables: IDisposable[]; possibleSessions: AuthenticationSession[] } }>();
private _accountBadgeDisposable = this._register(new MutableDisposable());
private readonly _accountBadgeDisposable = this._register(new MutableDisposable());
constructor(
@IActivityService private readonly activityService: IActivityService,

View File

@ -621,7 +621,7 @@ export class WorkspaceConfiguration extends Disposable {
private readonly _cachedConfiguration: CachedWorkspaceConfiguration;
private _workspaceConfiguration: CachedWorkspaceConfiguration | FileServiceBasedWorkspaceConfiguration;
private _workspaceConfigurationDisposables = this._register(new DisposableStore());
private readonly _workspaceConfigurationDisposables = this._register(new DisposableStore());
private _workspaceIdentifier: IWorkspaceIdentifier | null = null;
private _isWorkspaceTrusted: boolean = false;