diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d50e440c5e935..4275816f72360 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7,6 +7,15 @@ module ts { /* @internal */ export let checkTime = 0; + /* @internal */ + export function getSymbolId(symbol: Symbol): number { + if (!symbol.id) { + symbol.id = nextSymbolId++; + } + + return symbol.id; + } + export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker { let Symbol = objectAllocator.getSymbolConstructor(); let Type = objectAllocator.getTypeConstructor(); @@ -250,8 +259,8 @@ module ts { function getSymbolLinks(symbol: Symbol): SymbolLinks { if (symbol.flags & SymbolFlags.Transient) return symbol; - if (!symbol.id) symbol.id = nextSymbolId++; - return symbolLinks[symbol.id] || (symbolLinks[symbol.id] = {}); + var id = getSymbolId(symbol); + return symbolLinks[id] || (symbolLinks[id] = {}); } function getNodeLinks(node: Node): NodeLinks { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 68ac8d916fbcc..299ba52bdebd9 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -330,6 +330,9 @@ module Harness.LanguageService { getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] { return unwrapJSONCallResult(this.shim.getReferencesAtPosition(fileName, position)); } + findReferences(fileName: string, position: number): ts.ReferencedSymbol[] { + return unwrapJSONCallResult(this.shim.findReferences(fileName, position)); + } getOccurrencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] { return unwrapJSONCallResult(this.shim.getOccurrencesAtPosition(fileName, position)); } diff --git a/src/server/client.ts b/src/server/client.ts index 07c742db4f845..875e3ffdb5b7b 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -300,6 +300,11 @@ module ts.server { }); } + findReferences(fileName: string, position: number): ReferencedSymbol[]{ + // Not yet implemented. + return []; + } + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { diff --git a/src/services/services.ts b/src/services/services.ts index ba8b8c00b7d17..658f29f5ae78a 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -937,6 +937,7 @@ module ts { getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; @@ -1042,6 +1043,11 @@ module ts { containerName: string; } + export interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } + export enum SymbolDisplayPartKind { aliasName, className, @@ -3438,6 +3444,17 @@ module ts { }; } + function createDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo { + return { + fileName: node.getSourceFile().fileName, + textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()), + kind: symbolKind, + name: symbolName, + containerKind: undefined, + containerName + }; + } + /// Goto definition function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { synchronizeHostData(); @@ -3453,7 +3470,7 @@ module ts { if (isJumpStatementTarget(node)) { let labelName = (node).text; let label = getTargetLabel((node.parent), (node).text); - return label ? [getDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined; + return label ? [createDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined; } /// Triple slash reference comments @@ -3484,7 +3501,7 @@ module ts { // If this is an alias, and the request came at the declaration location // get the aliased symbol instead. This allows for goto def on an import e.g. // import {A, B} from "mod"; - // to jump to the implementation directelly. + // to jump to the implementation directly. if (symbol.flags & SymbolFlags.Alias) { let declaration = symbol.declarations[0]; if (node.kind === SyntaxKind.Identifier && node.parent === declaration) { @@ -3492,7 +3509,6 @@ module ts { } } - // Because name in short-hand property assignment has two different meanings: property name and property value, // using go-to-definition at such position should go to the variable declaration of the property value rather than // go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition @@ -3509,7 +3525,7 @@ module ts { let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol); let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node); return map(shorthandDeclarations, - declaration => getDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); + declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); } let result: DefinitionInfo[] = []; @@ -3523,21 +3539,31 @@ module ts { !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { // Just add all the declarations. forEach(declarations, declaration => { - result.push(getDefinitionInfo(declaration, symbolKind, symbolName, containerName)); + result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); }); } return result; - function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo { - return { - fileName: node.getSourceFile().fileName, - textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()), - kind: symbolKind, - name: symbolName, - containerKind: undefined, - containerName - }; + function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + // Applicable only if we are in a new expression, or we are on a constructor declaration + // and in either case the symbol has a construct signature definition, i.e. class + if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) { + if (symbol.flags & SymbolFlags.Class) { + let classDeclaration = symbol.getDeclarations()[0]; + Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration); + + return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result); + } + } + return false; + } + + function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { + return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result); + } + return false; } function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { @@ -3553,37 +3579,16 @@ module ts { }); if (definition) { - result.push(getDefinitionInfo(definition, symbolKind, symbolName, containerName)); + result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName)); return true; } else if (declarations.length) { - result.push(getDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); + result.push(createDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); return true; } return false; } - - function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { - // Applicable only if we are in a new expression, or we are on a constructor declaration - // and in either case the symbol has a construct signature definition, i.e. class - if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) { - if (symbol.flags & SymbolFlags.Class) { - let classDeclaration = symbol.getDeclarations()[0]; - Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration); - - return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result); - } - } - return false; - } - - function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { - if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { - return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result); - } - return false; - } } /// References and Occurrences @@ -3599,7 +3604,7 @@ module ts { if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { - return getReferencesForNode(node, [sourceFile], /*searchOnlyInCurrentFile*/ true, /*findInStrings:*/ false, /*findInComments:*/ false); + return convertReferences(getReferencesForNode(node, [sourceFile], /*searchOnlyInCurrentFile*/ true, /*findInStrings:*/ false, /*findInComments:*/ false)); } switch (node.kind) { @@ -3899,7 +3904,7 @@ module ts { return map(keywords, getReferenceEntryFromNode); } - function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) { + function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement): ReferenceEntry[] { let keywords: Node[] = []; pushKeywordIf(keywords, switchStatement.getFirstToken(), SyntaxKind.SwitchKeyword); @@ -4022,7 +4027,7 @@ module ts { } } - function getModifierOccurrences(modifier: SyntaxKind, declaration: Node) { + function getModifierOccurrences(modifier: SyntaxKind, declaration: Node): ReferenceEntry[] { let container = declaration.parent; // Make sure we only highlight the keyword when it makes sense to do so. @@ -4127,15 +4132,36 @@ module ts { } } - function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] { - return findReferences(fileName, position, findInStrings, findInComments); + function convertReferences(referenceSymbols: ReferencedSymbol[]): ReferenceEntry[]{ + if (!referenceSymbols) { + return undefined; + } + + let referenceEntries: ReferenceEntry[] = []; + for (let referenceSymbol of referenceSymbols) { + addRange(referenceEntries, referenceSymbol.references); + } + return referenceEntries; + } + + function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]{ + var referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments); + return convertReferences(referencedSymbols); } function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { - return findReferences(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + var referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + return convertReferences(referencedSymbols); + } + + function findReferences(fileName: string, position: number): ReferencedSymbol[]{ + var referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + + // Only include referenced symbols that have a valid definition. + return filter(referencedSymbols, rs => !!rs.definition); } - function findReferences(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferenceEntry[] { + function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); @@ -4158,14 +4184,14 @@ module ts { return getReferencesForNode(node, program.getSourceFiles(), /*searchOnlyInCurrentFile*/ false, findInStrings, findInComments); } - function getReferencesForNode(node: Node, sourceFiles: SourceFile[], searchOnlyInCurrentFile: boolean, findInStrings: boolean, findInComments: boolean): ReferenceEntry[] { + function getReferencesForNode(node: Node, sourceFiles: SourceFile[], searchOnlyInCurrentFile: boolean, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[]{ // Labels if (isLabelName(node)) { if (isJumpStatementTarget(node)) { let labelDefinition = getTargetLabel((node.parent), (node).text); // if we have a label definition, look within its statement for references, if not, then - // the label is undefined, just return a set of one for the current node. - return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntryFromNode(node)]; + // the label is undefined and we have no results.. + return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : undefined; } else { // it is a label definition and not a target, search within the parent labeledStatement @@ -4185,9 +4211,8 @@ module ts { // Could not find a symbol e.g. unknown identifier if (!symbol) { - // Even if we did not find a symbol, we have an identifier, so there is at least - // one reference that we know of. return that instead of undefined. - return [getReferenceEntryFromNode(node)]; + // Can't have references to something that we have no symbol for. + return undefined; } let declarations = symbol.declarations; @@ -4197,7 +4222,7 @@ module ts { return undefined; } - let result: ReferenceEntry[]; + let result: ReferencedSymbol[]; // Compute the meaning from the location and the symbol it references let searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); @@ -4209,15 +4234,18 @@ module ts { // otherwise we'll need to search globally (i.e. include each file). let scope = getSymbolScope(symbol); + // Maps from a symbol ID to the ReferencedSymbol entry in 'result'. + let symbolToIndex: number[] = []; + if (scope) { result = []; - getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); + getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); } else { if (searchOnlyInCurrentFile) { Debug.assert(sourceFiles.length === 1); result = []; - getReferencesInNode(sourceFiles[0], symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); + getReferencesInNode(sourceFiles[0], symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); } else { let internedName = getInternedName(symbol, node, declarations) @@ -4228,7 +4256,7 @@ module ts { if (lookUp(nameTable, internedName)) { result = result || []; - getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); + getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex); } }); } @@ -4236,6 +4264,24 @@ module ts { return result; + function getDefinition(symbol: Symbol): DefinitionInfo { + let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), typeInfoResolver, node); + let name = map(info.displayParts, p => p.text).join(""); + let declarations = symbol.declarations; + if (!declarations || declarations.length === 0) { + return undefined; + } + + return { + containerKind: "", + containerName: "", + name, + kind: info.symbolKind, + fileName: declarations[0].getSourceFile().fileName, + textSpan: createTextSpan(declarations[0].getStart(), 0) + }; + } + function isImportOrExportSpecifierName(location: Node): boolean { return location.parent && (location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) && @@ -4393,8 +4439,8 @@ module ts { return positions; } - function getLabelReferencesInNode(container: Node, targetLabel: Identifier): ReferenceEntry[] { - let result: ReferenceEntry[] = []; + function getLabelReferencesInNode(container: Node, targetLabel: Identifier): ReferencedSymbol[] { + let references: ReferenceEntry[] = []; let sourceFile = container.getSourceFile(); let labelName = targetLabel.text; let possiblePositions = getPossibleSymbolReferencePositions(sourceFile, labelName, container.getStart(), container.getEnd()); @@ -4409,10 +4455,20 @@ module ts { // Only pick labels that are either the target label, or have a target that is the target label if (node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { - result.push(getReferenceEntryFromNode(node)); + references.push(getReferenceEntryFromNode(node)); } }); - return result; + + var definition: DefinitionInfo = { + containerKind: "", + containerName: "", + fileName: targetLabel.getSourceFile().fileName, + kind: ScriptElementKind.label, + name: labelName, + textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()) + } + + return [{ definition, references }]; } function isValidReferencePosition(node: Node, searchSymbolName: string): boolean { @@ -4452,7 +4508,9 @@ module ts { searchMeaning: SemanticMeaning, findInStrings: boolean, findInComments: boolean, - result: ReferenceEntry[]): void { + result: ReferencedSymbol[], + symbolToIndex: number[]): void { + let sourceFile = container.getSourceFile(); let tripleSlashDirectivePrefixRegex = /^\/\/\/\s*= 0) { - result.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name)); + var referencedSymbol = getReferencedSymbol(shorthandValueSymbol); + referencedSymbol.references.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name)); } } }); } + return; + + function getReferencedSymbol(symbol: Symbol): ReferencedSymbol { + var symbolId = getSymbolId(symbol); + var index = symbolToIndex[symbolId]; + if (index === undefined) { + index = result.length; + symbolToIndex[symbolId] = index; + + result.push({ + definition: getDefinition(symbol), + references: [] + }); + } + + return result[index]; + } + function isInString(position: number) { let token = getTokenAtPosition(sourceFile, position); return token && token.kind === SyntaxKind.StringLiteral && position > token.getStart(); @@ -4532,7 +4620,7 @@ module ts { } } - function getReferencesForSuperKeyword(superKeyword: Node): ReferenceEntry[] { + function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] { let searchSpaceNode = getSuperContainer(superKeyword, /*includeFunctions*/ false); if (!searchSpaceNode) { return undefined; @@ -4555,7 +4643,7 @@ module ts { return undefined; } - let result: ReferenceEntry[] = []; + let references: ReferenceEntry[] = []; let sourceFile = searchSpaceNode.getSourceFile(); let possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); @@ -4574,14 +4662,15 @@ module ts { // Now make sure the owning class is the same as the search-space // and has the same static qualifier as the original 'super's owner. if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { - result.push(getReferenceEntryFromNode(node)); + references.push(getReferenceEntryFromNode(node)); } }); - return result; + var definition = getDefinition(searchSpaceNode.symbol); + return [{ definition, references }]; } - function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferenceEntry[] { + function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferencedSymbol[] { let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); // Whether 'this' occurs in a static context within a class. @@ -4616,22 +4705,32 @@ module ts { return undefined; } - let result: ReferenceEntry[] = []; + let references: ReferenceEntry[] = []; let possiblePositions: number[]; if (searchSpaceNode.kind === SyntaxKind.SourceFile) { forEach(sourceFiles, sourceFile => { possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); - getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, result); + getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, references); }); } else { let sourceFile = searchSpaceNode.getSourceFile(); possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); - getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result); + getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references); } - return result; + return [{ + definition: { + containerKind: "", + containerName: "", + fileName: node.getSourceFile().fileName, + kind: ScriptElementKind.variableElement, + name: "this", + textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()) + }, + references: references + }]; function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: ReferenceEntry[]): void { forEach(possiblePositions, position => { @@ -4754,16 +4853,18 @@ module ts { } } - function isRelatableToSearchSet(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node): boolean { + function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node): Symbol { if (searchSymbols.indexOf(referenceSymbol) >= 0) { - return true; + return referenceSymbol; } // If the reference symbol is an alias, check if what it is aliasing is one of the search // symbols. - if (isImportOrExportSpecifierImportSymbol(referenceSymbol) && - searchSymbols.indexOf(typeInfoResolver.getAliasedSymbol(referenceSymbol)) >= 0) { - return true; + if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { + var aliasedSymbol = typeInfoResolver.getAliasedSymbol(referenceSymbol); + if (searchSymbols.indexOf(aliasedSymbol) >= 0) { + return aliasedSymbol; + } } // If the reference location is in an object literal, try to get the contextual type for the @@ -4771,7 +4872,7 @@ module ts { // compare to our searchSymbol if (isNameOfPropertyAssignment(referenceLocation)) { return forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => { - return forEach(typeInfoResolver.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0); + return forEach(typeInfoResolver.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); }); } @@ -4780,7 +4881,7 @@ module ts { return forEach(typeInfoResolver.getRootSymbols(referenceSymbol), rootSymbol => { // if it is in the list, then we are done if (searchSymbols.indexOf(rootSymbol) >= 0) { - return true; + return rootSymbol; } // Finally, try all properties with the same name in any type the containing type extended or implemented, and @@ -4788,10 +4889,10 @@ module ts { if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { let result: Symbol[] = []; getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result); - return forEach(result, s => searchSymbols.indexOf(s) >= 0); + return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined); } - return false; + return undefined; }); } @@ -5747,6 +5848,7 @@ module ts { getQuickInfoAtPosition, getDefinitionAtPosition, getReferencesAtPosition, + findReferences, getOccurrencesAtPosition, getNameOrDottedNameSpan, getBreakpointStatementAtPosition, diff --git a/src/services/shims.ts b/src/services/shims.ts index 63e3c9e23aec6..adcec5ada2b60 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -127,6 +127,12 @@ module ts { * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[] */ getReferencesAtPosition(fileName: string, position: number): string; + + /** + * Returns a JSON-encoded value of the type: + * { definition: ; references: [] }[] + */ + findReferences(fileName: string, position: number): string; /** * Returns a JSON-encoded value of the type: @@ -555,11 +561,6 @@ module ts { /// GET REFERENCES - /** - * Return references to a symbol at the requested position. - * References are separated by "\n". - * Each reference is a "fileindex min lim" sub-string. - */ public getReferencesAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( "getReferencesAtPosition('" + fileName + "', " + position + ")", @@ -568,6 +569,14 @@ module ts { }); } + public findReferences(fileName: string, position: number): string { + return this.forwardJSONCall( + "findReferences('" + fileName + "', " + position + ")", + () => { + return this.languageService.findReferences(fileName, position); + }); + } + public getOccurrencesAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( "getOccurrencesAtPosition('" + fileName + "', " + position + ")", diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index b8f4c7cdd136b..0fd72e8015824 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1589,6 +1589,7 @@ declare module "typescript" { getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getOutliningSpans(fileName: string): OutliningSpan[]; @@ -1675,6 +1676,10 @@ declare module "typescript" { containerKind: string; containerName: string; } + interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } enum SymbolDisplayPartKind { aliasName = 0, className = 1, diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index e1d9aa5896188..28763a896ddfe 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -5154,6 +5154,12 @@ declare module "typescript" { >position : number >ReferenceEntry : ReferenceEntry + findReferences(fileName: string, position: number): ReferencedSymbol[]; +>findReferences : (fileName: string, position: number) => ReferencedSymbol[] +>fileName : string +>position : number +>ReferencedSymbol : ReferencedSymbol + getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; >getNavigateToItems : (searchValue: string, maxResultCount?: number) => NavigateToItem[] >searchValue : string @@ -5424,6 +5430,17 @@ declare module "typescript" { containerName: string; >containerName : string + } + interface ReferencedSymbol { +>ReferencedSymbol : ReferencedSymbol + + definition: DefinitionInfo; +>definition : DefinitionInfo +>DefinitionInfo : DefinitionInfo + + references: ReferenceEntry[]; +>references : ReferenceEntry[] +>ReferenceEntry : ReferenceEntry } enum SymbolDisplayPartKind { >SymbolDisplayPartKind : SymbolDisplayPartKind diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 4e3af8d1be096..a947821455de8 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1620,6 +1620,7 @@ declare module "typescript" { getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getOutliningSpans(fileName: string): OutliningSpan[]; @@ -1706,6 +1707,10 @@ declare module "typescript" { containerKind: string; containerName: string; } + interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } enum SymbolDisplayPartKind { aliasName = 0, className = 1, diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 7cf542f0b40f6..34dc65aa351d1 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -5300,6 +5300,12 @@ declare module "typescript" { >position : number >ReferenceEntry : ReferenceEntry + findReferences(fileName: string, position: number): ReferencedSymbol[]; +>findReferences : (fileName: string, position: number) => ReferencedSymbol[] +>fileName : string +>position : number +>ReferencedSymbol : ReferencedSymbol + getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; >getNavigateToItems : (searchValue: string, maxResultCount?: number) => NavigateToItem[] >searchValue : string @@ -5570,6 +5576,17 @@ declare module "typescript" { containerName: string; >containerName : string + } + interface ReferencedSymbol { +>ReferencedSymbol : ReferencedSymbol + + definition: DefinitionInfo; +>definition : DefinitionInfo +>DefinitionInfo : DefinitionInfo + + references: ReferenceEntry[]; +>references : ReferenceEntry[] +>ReferenceEntry : ReferenceEntry } enum SymbolDisplayPartKind { >SymbolDisplayPartKind : SymbolDisplayPartKind diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 261ad5b25f6fe..00c2c63ac1031 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1621,6 +1621,7 @@ declare module "typescript" { getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getOutliningSpans(fileName: string): OutliningSpan[]; @@ -1707,6 +1708,10 @@ declare module "typescript" { containerKind: string; containerName: string; } + interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } enum SymbolDisplayPartKind { aliasName = 0, className = 1, diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index eb4c7ab122f89..c5b769888dbb3 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -5250,6 +5250,12 @@ declare module "typescript" { >position : number >ReferenceEntry : ReferenceEntry + findReferences(fileName: string, position: number): ReferencedSymbol[]; +>findReferences : (fileName: string, position: number) => ReferencedSymbol[] +>fileName : string +>position : number +>ReferencedSymbol : ReferencedSymbol + getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; >getNavigateToItems : (searchValue: string, maxResultCount?: number) => NavigateToItem[] >searchValue : string @@ -5520,6 +5526,17 @@ declare module "typescript" { containerName: string; >containerName : string + } + interface ReferencedSymbol { +>ReferencedSymbol : ReferencedSymbol + + definition: DefinitionInfo; +>definition : DefinitionInfo +>DefinitionInfo : DefinitionInfo + + references: ReferenceEntry[]; +>references : ReferenceEntry[] +>ReferenceEntry : ReferenceEntry } enum SymbolDisplayPartKind { >SymbolDisplayPartKind : SymbolDisplayPartKind diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index a821bc5011d74..91039f112b7f3 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1658,6 +1658,7 @@ declare module "typescript" { getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + findReferences(fileName: string, position: number): ReferencedSymbol[]; getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getOutliningSpans(fileName: string): OutliningSpan[]; @@ -1744,6 +1745,10 @@ declare module "typescript" { containerKind: string; containerName: string; } + interface ReferencedSymbol { + definition: DefinitionInfo; + references: ReferenceEntry[]; + } enum SymbolDisplayPartKind { aliasName = 0, className = 1, diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 47e5a0147fd00..09322aaa77135 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -5423,6 +5423,12 @@ declare module "typescript" { >position : number >ReferenceEntry : ReferenceEntry + findReferences(fileName: string, position: number): ReferencedSymbol[]; +>findReferences : (fileName: string, position: number) => ReferencedSymbol[] +>fileName : string +>position : number +>ReferencedSymbol : ReferencedSymbol + getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[]; >getNavigateToItems : (searchValue: string, maxResultCount?: number) => NavigateToItem[] >searchValue : string @@ -5693,6 +5699,17 @@ declare module "typescript" { containerName: string; >containerName : string + } + interface ReferencedSymbol { +>ReferencedSymbol : ReferencedSymbol + + definition: DefinitionInfo; +>definition : DefinitionInfo +>DefinitionInfo : DefinitionInfo + + references: ReferenceEntry[]; +>references : ReferenceEntry[] +>ReferenceEntry : ReferenceEntry } enum SymbolDisplayPartKind { >SymbolDisplayPartKind : SymbolDisplayPartKind diff --git a/tests/cases/fourslash/findAllRefsInsideWithBlock.ts b/tests/cases/fourslash/findAllRefsInsideWithBlock.ts index 394d30d89d39d..fc8a94eaa2d24 100644 --- a/tests/cases/fourslash/findAllRefsInsideWithBlock.ts +++ b/tests/cases/fourslash/findAllRefsInsideWithBlock.ts @@ -13,4 +13,4 @@ goTo.marker('1'); verify.referencesCountIs(3); goTo.marker('2'); -verify.referencesCountIs(1); \ No newline at end of file +verify.referencesCountIs(0); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesOfUndefinedSymbol.ts b/tests/cases/fourslash/getOccurrencesOfUndefinedSymbol.ts index 4893a6079d1da..96c3cdc2e39ae 100644 --- a/tests/cases/fourslash/getOccurrencesOfUndefinedSymbol.ts +++ b/tests/cases/fourslash/getOccurrencesOfUndefinedSymbol.ts @@ -17,4 +17,4 @@ // "any" should not be highlighted goTo.marker(); -verify.occurrencesAtPositionCount(1); +verify.occurrencesAtPositionCount(0); diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultBroken.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultBroken.ts index 018280a403249..25ee54f8115af 100644 --- a/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultBroken.ts +++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultBroken.ts @@ -39,8 +39,6 @@ for (var i = 1; i <= test.markers().length; i++) { verify.occurrencesAtPositionCount(8); break; case 4: - case 5: - case 8: verify.occurrencesAtPositionCount(1); break; case 6: @@ -48,6 +46,8 @@ for (var i = 1; i <= test.markers().length; i++) { case 9: verify.occurrencesAtPositionCount(8); break; + case 5: + case 8: case 10: case 11: case 12: diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives2.ts b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts index 65fb37d09b4df..0a8b5860feb37 100644 --- a/tests/cases/fourslash/getOccurrencesThisNegatives2.ts +++ b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts @@ -143,5 +143,5 @@ test.markers().forEach(m => { goTo.position(m.position, m.fileName) - verify.occurrencesAtPositionCount(1); + verify.occurrencesAtPositionCount(0); }); diff --git a/tests/cases/fourslash/getOccurrencesTryCatchFinallyBroken.ts b/tests/cases/fourslash/getOccurrencesTryCatchFinallyBroken.ts index c866ed9639846..01a202a677cf5 100644 --- a/tests/cases/fourslash/getOccurrencesTryCatchFinallyBroken.ts +++ b/tests/cases/fourslash/getOccurrencesTryCatchFinallyBroken.ts @@ -36,6 +36,8 @@ for (var i = 1; i <= test.markers().length; i++) { switch (i) { case 1: + verify.occurrencesAtPositionCount(0); + break; case 2: case 3: verify.occurrencesAtPositionCount(1); diff --git a/tests/cases/fourslash/localGetReferences.ts b/tests/cases/fourslash/localGetReferences.ts index 6d5f541dd513b..e5873efeeb4be 100644 --- a/tests/cases/fourslash/localGetReferences.ts +++ b/tests/cases/fourslash/localGetReferences.ts @@ -223,7 +223,7 @@ verify.referencesCountIs(7); // References to unresolved symbol. goTo.marker("12"); -verify.referencesCountIs(1); +verify.referencesCountIs(0); // References to no context. goTo.marker("13"); diff --git a/tests/cases/fourslash/referencesForIllegalAssignment.ts b/tests/cases/fourslash/referencesForIllegalAssignment.ts index 81a45f6415394..403bf0432a7b0 100644 --- a/tests/cases/fourslash/referencesForIllegalAssignment.ts +++ b/tests/cases/fourslash/referencesForIllegalAssignment.ts @@ -6,10 +6,10 @@ ////ba/*4*/r = b/*5*/ar + 1; goTo.marker("1"); -verify.referencesCountIs(1); +verify.referencesCountIs(0); goTo.marker("2"); -verify.referencesCountIs(1); +verify.referencesCountIs(0); goTo.marker("3"); verify.referencesCountIs(3); diff --git a/tests/cases/fourslash/referencesForIndexProperty2.ts b/tests/cases/fourslash/referencesForIndexProperty2.ts index fd9cf0e7183e4..9dcba3163c696 100644 --- a/tests/cases/fourslash/referencesForIndexProperty2.ts +++ b/tests/cases/fourslash/referencesForIndexProperty2.ts @@ -6,4 +6,4 @@ ////a[/*1*/"blah"]; goTo.marker("1"); -verify.referencesCountIs(1); \ No newline at end of file +verify.referencesCountIs(0); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForLabel2.ts b/tests/cases/fourslash/referencesForLabel2.ts index 054ce56286443..ccb441d60b9da 100644 --- a/tests/cases/fourslash/referencesForLabel2.ts +++ b/tests/cases/fourslash/referencesForLabel2.ts @@ -9,4 +9,4 @@ ////} goTo.marker("1"); -verify.referencesCountIs(1); +verify.referencesCountIs(0);