From 379d03b5a732824e561bc4c67e5232431c260c7c Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 22 Jan 2015 18:20:40 -0800 Subject: [PATCH 1/3] use nameTable - services layer storage of identifiers in the file --- src/services/services.ts | 64 +++++++++++++++---- .../fourslash/getOccurrencesAfterEdit.ts | 15 +++++ 2 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 tests/cases/fourslash/getOccurrencesAfterEdit.ts diff --git a/src/services/services.ts b/src/services/services.ts index 84e5e7fefa5f6..e662f6f2de1c1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -59,7 +59,7 @@ module ts { isOpen: boolean; version: string; scriptSnapshot: IScriptSnapshot; - + nameTable: Map; getNamedDeclarations(): Declaration[]; } @@ -750,6 +750,7 @@ module ts { public isOpen: boolean; public languageVersion: ScriptTarget; public identifiers: Map; + public nameTable: Map; private namedDeclarations: Declaration[]; @@ -1546,6 +1547,8 @@ module ts { export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, isOpen: boolean, setNodeParents: boolean): SourceFile { var sourceFile = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents); setSourceFileFields(sourceFile, scriptSnapshot, version, isOpen); + // after full parsing we can use table with interned strings as name table + sourceFile.nameTable = sourceFile.identifiers; return sourceFile; } @@ -1577,6 +1580,9 @@ module ts { if (!disableIncrementalParsing) { var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen); + // after incremental parsing nameTable might not be up-to-date + // drop it so it can be lazily recreated later + newSourceFile.nameTable = undefined; return newSourceFile; } } @@ -3235,7 +3241,7 @@ module ts { if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { - return getReferencesForNode(node, [sourceFile], /*findInStrings:*/ false, /*findInComments:*/ false); + return getReferencesForNode(node, [sourceFile], /*searchOnlyInCurrentFile*/ true, /*findInStrings:*/ false, /*findInComments:*/ false); } switch (node.kind) { @@ -3788,10 +3794,31 @@ module ts { } Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral); - return getReferencesForNode(node, program.getSourceFiles(), findInStrings, findInComments); + return getReferencesForNode(node, program.getSourceFiles(), /*searchOnlyInCurrentFile*/ false, findInStrings, findInComments); + } + + function initializeNameTable(sourceFile: SourceFile): void { + var nameTable: Map = {}; + + walk(sourceFile); + sourceFile.nameTable = nameTable; + + function walk(node: Node) { + switch (node.kind) { + case SyntaxKind.Identifier: + nameTable[(node).text] = (node).text; + break; + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + nameTable[(node).text] = (node).text; + break; + default: + forEachChild(node, walk); + } + } } - function getReferencesForNode(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferenceEntry[] { + function getReferencesForNode(node: Node, sourceFiles: SourceFile[], searchOnlyInCurrentFile: boolean, findInStrings: boolean, findInComments: boolean): ReferenceEntry[] { // Labels if (isLabelName(node)) { if (isJumpStatementTarget(node)) { @@ -3847,15 +3874,28 @@ module ts { getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); } else { - var internedName = getInternedName(symbol, declarations) - forEach(sourceFiles, sourceFile => { - cancellationToken.throwIfCancellationRequested(); + if (searchOnlyInCurrentFile) { + Debug.assert(sourceFiles.length === 1); + result = []; + getReferencesInNode(sourceFiles[0], symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); + } + else { + var internedName = getInternedName(symbol, declarations) + forEach(sourceFiles, sourceFile => { + cancellationToken.throwIfCancellationRequested(); - if (lookUp(sourceFile.identifiers, internedName)) { - result = result || []; - getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); - } - }); + if (!sourceFile.nameTable) { + initializeNameTable(sourceFile) + } + + Debug.assert(sourceFile.nameTable !== undefined); + + if (lookUp(sourceFile.nameTable, internedName)) { + result = result || []; + getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); + } + }); + } } return result; diff --git a/tests/cases/fourslash/getOccurrencesAfterEdit.ts b/tests/cases/fourslash/getOccurrencesAfterEdit.ts new file mode 100644 index 0000000000000..f878da9356d2d --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesAfterEdit.ts @@ -0,0 +1,15 @@ +/// + +/////*0*/ +////function f(s: string) { +//// s.con/*1*/structor +////} + +goTo.marker("1"); +verify.occurrencesAtPositionCount(1); + +goTo.marker("0"); +edit.insert("\r\n"); + +goTo.marker("1"); +verify.occurrencesAtPositionCount(1); \ No newline at end of file From 6040e55fa42fdb0877c0f062840667a7f3ea9c54 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 23 Jan 2015 15:36:36 -0800 Subject: [PATCH 2/3] add 'find all references' test --- .../fourslash/findReferencesAfterEdit.ts | 22 +++++++++++++++++++ .../cases/fourslash/getOccurencesAfterEdit.ts | 18 +++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/cases/fourslash/findReferencesAfterEdit.ts create mode 100644 tests/cases/fourslash/getOccurencesAfterEdit.ts diff --git a/tests/cases/fourslash/findReferencesAfterEdit.ts b/tests/cases/fourslash/findReferencesAfterEdit.ts new file mode 100644 index 0000000000000..5eca1a3b8f2f4 --- /dev/null +++ b/tests/cases/fourslash/findReferencesAfterEdit.ts @@ -0,0 +1,22 @@ +/// + +// @Filename: a.ts +////interface A { +//// foo: string; +////} + +// @Filename: b.ts +/////// +/////*0*/ +////function foo(x: A) { +//// x.f/*1*/oo +////} + +goTo.marker("1"); +verify.referencesCountIs(2); + +goTo.marker("0"); +edit.insert("\r\n"); + +goTo.marker("1"); +verify.referencesCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurencesAfterEdit.ts b/tests/cases/fourslash/getOccurencesAfterEdit.ts new file mode 100644 index 0000000000000..0654cc3962c20 --- /dev/null +++ b/tests/cases/fourslash/getOccurencesAfterEdit.ts @@ -0,0 +1,18 @@ +/// + +/////*0*/ +////interface A { +//// foo: string; +////} +////function foo(x: A) { +//// x.f/*1*/oo +////} + +goTo.marker("1"); +verify.occurrencesAtPositionCount(2); + +goTo.marker("0"); +edit.insert("\r\n"); + +goTo.marker("1"); +verify.occurrencesAtPositionCount(2); \ No newline at end of file From da6070bcf755e1f36cb8b61f8658f0d08a41c7ce Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 23 Jan 2015 15:39:50 -0800 Subject: [PATCH 3/3] fixed typo in test name --- .../cases/fourslash/getOccurencesAfterEdit.ts | 18 ------------------ .../cases/fourslash/getOccurrencesAfterEdit.ts | 11 +++++++---- 2 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 tests/cases/fourslash/getOccurencesAfterEdit.ts diff --git a/tests/cases/fourslash/getOccurencesAfterEdit.ts b/tests/cases/fourslash/getOccurencesAfterEdit.ts deleted file mode 100644 index 0654cc3962c20..0000000000000 --- a/tests/cases/fourslash/getOccurencesAfterEdit.ts +++ /dev/null @@ -1,18 +0,0 @@ -/// - -/////*0*/ -////interface A { -//// foo: string; -////} -////function foo(x: A) { -//// x.f/*1*/oo -////} - -goTo.marker("1"); -verify.occurrencesAtPositionCount(2); - -goTo.marker("0"); -edit.insert("\r\n"); - -goTo.marker("1"); -verify.occurrencesAtPositionCount(2); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesAfterEdit.ts b/tests/cases/fourslash/getOccurrencesAfterEdit.ts index f878da9356d2d..0654cc3962c20 100644 --- a/tests/cases/fourslash/getOccurrencesAfterEdit.ts +++ b/tests/cases/fourslash/getOccurrencesAfterEdit.ts @@ -1,15 +1,18 @@ /// /////*0*/ -////function f(s: string) { -//// s.con/*1*/structor +////interface A { +//// foo: string; +////} +////function foo(x: A) { +//// x.f/*1*/oo ////} goTo.marker("1"); -verify.occurrencesAtPositionCount(1); +verify.occurrencesAtPositionCount(2); goTo.marker("0"); edit.insert("\r\n"); goTo.marker("1"); -verify.occurrencesAtPositionCount(1); \ No newline at end of file +verify.occurrencesAtPositionCount(2); \ No newline at end of file