Fix memory leak in .maintainLanguageMode

This commit is contained in:
Max Brunsfeld
2017-11-22 11:41:55 -08:00
parent cbdae916dd
commit 4810d13094
2 changed files with 64 additions and 19 deletions

View File

@@ -63,7 +63,7 @@ describe('GrammarRegistry', () => {
})
})
describe('.maintainLanguageMode', () => {
describe('.maintainLanguageMode(buffer)', () => {
it('assigns a grammar to the buffer based on its path', async () => {
const buffer = new TextBuffer()
@@ -128,24 +128,55 @@ describe('GrammarRegistry', () => {
expect(retainedBufferCount(grammarRegistry)).toBe(0)
})
describe('when called twice with a given buffer', () => {
it('does nothing the second time', async () => {
const buffer = new TextBuffer()
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
const disposable1 = grammarRegistry.maintainLanguageMode(buffer)
const disposable2 = grammarRegistry.maintainLanguageMode(buffer)
it('doesn\'t do anything when called a second time with the same buffer', async () => {
const buffer = new TextBuffer()
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
const disposable1 = grammarRegistry.maintainLanguageMode(buffer)
const disposable2 = grammarRegistry.maintainLanguageMode(buffer)
buffer.setPath('test.js')
expect(buffer.getLanguageMode().getLanguageName()).toBe('JavaScript')
buffer.setPath('test.js')
expect(buffer.getLanguageMode().getLanguageName()).toBe('JavaScript')
disposable2.dispose()
buffer.setPath('test.txt')
expect(buffer.getLanguageMode().getLanguageName()).toBe('Null Grammar')
disposable2.dispose()
buffer.setPath('test.txt')
expect(buffer.getLanguageMode().getLanguageName()).toBe('Null Grammar')
disposable1.dispose()
buffer.setPath('test.js')
expect(buffer.getLanguageMode().getLanguageName()).toBe('Null Grammar')
})
disposable1.dispose()
buffer.setPath('test.js')
expect(buffer.getLanguageMode().getLanguageName()).toBe('Null Grammar')
})
it('does not retain the buffer after the buffer is destroyed', () => {
const buffer = new TextBuffer()
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
const disposable = grammarRegistry.maintainLanguageMode(buffer)
expect(retainedBufferCount(grammarRegistry)).toBe(1)
expect(subscriptionCount(grammarRegistry)).toBe(2)
buffer.destroy()
expect(retainedBufferCount(grammarRegistry)).toBe(0)
expect(subscriptionCount(grammarRegistry)).toBe(0)
expect(buffer.emitter.getTotalListenerCount()).toBe(0)
disposable.dispose()
expect(retainedBufferCount(grammarRegistry)).toBe(0)
expect(subscriptionCount(grammarRegistry)).toBe(0)
})
it('does not retain the buffer when the grammar registry is destroyed', () => {
const buffer = new TextBuffer()
grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson'))
const disposable = grammarRegistry.maintainLanguageMode(buffer)
expect(retainedBufferCount(grammarRegistry)).toBe(1)
expect(subscriptionCount(grammarRegistry)).toBe(2)
grammarRegistry.clear()
expect(retainedBufferCount(grammarRegistry)).toBe(0)
expect(subscriptionCount(grammarRegistry)).toBe(0)
expect(buffer.emitter.getTotalListenerCount()).toBe(0)
})
})
@@ -357,3 +388,7 @@ describe('GrammarRegistry', () => {
function retainedBufferCount (grammarRegistry) {
return grammarRegistry.grammarScoresByBuffer.size
}
function subscriptionCount (grammarRegistry) {
return grammarRegistry.subscriptions.disposables.size
}

View File

@@ -71,12 +71,22 @@ class GrammarRegistry extends FirstMate.GrammarRegistry {
}
})
this.subscriptions.add(pathChangeSubscription)
const destroySubscription = buffer.onDidDestroy(() => {
this.grammarScoresByBuffer.delete(buffer)
this.languageNameOverridesByBufferId.delete(buffer.id)
this.subscriptions.remove(destroySubscription)
this.subscriptions.remove(pathChangeSubscription)
})
this.subscriptions.add(pathChangeSubscription, destroySubscription)
return new Disposable(() => {
this.subscriptions.remove(pathChangeSubscription)
this.grammarScoresByBuffer.delete(buffer)
destroySubscription.dispose()
pathChangeSubscription.dispose()
this.subscriptions.remove(pathChangeSubscription)
this.subscriptions.remove(destroySubscription)
this.grammarScoresByBuffer.delete(buffer)
this.languageNameOverridesByBufferId.delete(buffer.id)
})
}