Merge pull request #13523 from atom/mb-ns-mitigate-leaks

Reduce the impact of leaking Editor, Selection, & Cursor objects
This commit is contained in:
Max Brunsfeld
2017-01-03 16:07:38 -08:00
committed by GitHub
6 changed files with 37 additions and 18 deletions

View File

@@ -65,7 +65,7 @@
"sinon": "1.17.4",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "10.2.1",
"text-buffer": "10.2.2",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"winreg": "^1.2.1",
@@ -101,7 +101,7 @@
"dev-live-reload": "0.47.0",
"encoding-selector": "0.22.0",
"exception-reporting": "0.40.1",
"find-and-replace": "0.205.0",
"find-and-replace": "0.205.1",
"fuzzy-finder": "1.4.1",
"git-diff": "1.2.0",
"go-to-line": "0.31.2",
@@ -118,7 +118,7 @@
"package-generator": "1.0.2",
"settings-view": "0.244.0",
"snippets": "1.0.4",
"spell-check": "0.70.1",
"spell-check": "0.70.2",
"status-bar": "1.7.0",
"styleguide": "0.48.0",
"symbols-view": "0.114.0",
@@ -127,7 +127,7 @@
"tree-view": "0.212.0",
"update-package-dependencies": "0.10.0",
"welcome": "0.35.2",
"whitespace": "0.36.0",
"whitespace": "0.36.1",
"wrap-guide": "0.39.0",
"language-c": "0.54.1",
"language-clojure": "0.22.1",

View File

@@ -81,8 +81,9 @@ describe "Selection", ->
describe "when the selection is destroyed", ->
it "destroys its marker", ->
selection.setBufferRange([[2, 0], [2, 10]])
marker = selection.marker
selection.destroy()
expect(selection.marker.isDestroyed()).toBeTruthy()
expect(marker.isDestroyed()).toBeTruthy()
describe ".insertText(text, options)", ->
it "allows pasting white space only lines when autoIndent is enabled", ->

View File

@@ -2181,7 +2181,7 @@ describe "TextEditorPresenter", ->
editor.getSelections()[2].setBufferRange([[1, 4], [1, 8]], autoscroll: false)
waitsForStateToUpdate presenter
destroyedSelection = null
[destroyedSelection, destroyedDecoration] = []
runs ->
expectValues stateForSelectionInTile(presenter, 2, 0), {
regions: [{top: 10, left: 4 * 10, width: 4 * 10, height: 10}]
@@ -2189,10 +2189,11 @@ describe "TextEditorPresenter", ->
# destroying
destroyedSelection = editor.getSelections()[2]
destroyedDecoration = destroyedSelection.decoration
waitsForStateToUpdate presenter, -> destroyedSelection.destroy()
runs ->
expectUndefinedStateForHighlight(presenter, destroyedSelection.decoration)
expectUndefinedStateForHighlight(presenter, destroyedDecoration)
it "updates when highlight decorations' properties are updated", ->
marker = editor.markBufferPosition([2, 2])

View File

@@ -4325,15 +4325,10 @@ describe "TextEditor", ->
expect(editor.getLastSelection().isEmpty()).toBeTruthy()
it "does not explode if the current language mode has no comment regex", ->
editor.destroy()
waitsForPromise ->
atom.workspace.open(null, autoIndent: false).then (o) -> editor = o
runs ->
editor.setSelectedBufferRange([[4, 5], [4, 5]])
editor.toggleLineCommentsInSelection()
expect(buffer.lineForRow(4)).toBe " while(items.length > 0) {"
editor = new TextEditor(buffer: new TextBuffer(text: 'hello'))
editor.setSelectedBufferRange([[0, 0], [0, 5]])
editor.toggleLineCommentsInSelection()
expect(editor.lineTextForBufferRow(0)).toBe "hello"
it "does nothing for empty lines and null grammar", ->
runs ->
@@ -5056,11 +5051,13 @@ describe "TextEditor", ->
describe ".destroy()", ->
it "destroys marker layers associated with the text editor", ->
buffer.retain()
selectionsMarkerLayerId = editor.selectionsMarkerLayer.id
foldsMarkerLayerId = editor.displayLayer.foldsMarkerLayer.id
editor.destroy()
expect(buffer.getMarkerLayer(selectionsMarkerLayerId)).toBeUndefined()
expect(buffer.getMarkerLayer(foldsMarkerLayerId)).toBeUndefined()
buffer.release()
it "notifies ::onDidDestroy observers when the editor is destroyed", ->
destroyObserverCalled = false
@@ -5069,6 +5066,23 @@ describe "TextEditor", ->
editor.destroy()
expect(destroyObserverCalled).toBe true
it "does not blow up when query methods are called afterward", ->
editor.destroy()
editor.getGrammar()
editor.getLastCursor()
editor.lineTextForBufferRow(0)
it "emits the destroy event after destroying the editor's buffer", ->
events = []
editor.getBuffer().onDidDestroy ->
expect(editor.isDestroyed()).toBe(true)
events.push('buffer-destroyed')
editor.onDidDestroy ->
expect(buffer.isDestroyed()).toBe(true)
events.push('editor-destroyed')
editor.destroy()
expect(events).toEqual(['buffer-destroyed', 'editor-destroyed'])
describe ".joinLines()", ->
describe "when no text is selected", ->
describe "when the line below isn't empty", ->

View File

@@ -410,14 +410,15 @@ class TextEditor extends Model
destroyed: ->
@disposables.dispose()
@displayLayer.destroy()
@disposables.dispose()
@tokenizedBuffer.destroy()
selection.destroy() for selection in @selections.slice()
@selectionsMarkerLayer.destroy()
@buffer.release()
@languageMode.destroy()
@gutterContainer.destroy()
@emitter.emit 'did-destroy'
@emitter.clear()
@editorElement = null
@presenter = null
###
Section: Event Subscription

View File

@@ -41,6 +41,7 @@ class TokenizedBuffer extends Model
destroyed: ->
@disposables.dispose()
@tokenizedLines.length = 0
buildIterator: ->
new TokenizedBufferIterator(this)
@@ -94,6 +95,7 @@ class TokenizedBuffer extends Model
false
retokenizeLines: ->
return unless @alive
@fullyTokenized = false
@tokenizedLines = new Array(@buffer.getLineCount())
@invalidRows = []