Add a new findReferences API that buckets results with the definition they matched against.

This commit is contained in:
Cyrus Najmabadi 2015-03-20 14:31:36 -07:00
parent 0d2a5bbf7c
commit cbeeb519b1
22 changed files with 364 additions and 167 deletions

View File

@ -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 <TransientSymbol>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 {

View File

@ -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));
}

View File

@ -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 = {

View File

@ -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,111 @@ 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
};
}
function getDefinitionInfos(node: Node, symbol: Symbol): DefinitionInfo[] {
// 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 directly.
if (symbol.flags & SymbolFlags.Alias) {
let declaration = symbol.declarations[0];
if (node.kind === SyntaxKind.Identifier && node.parent === declaration) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
}
}
// 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
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
let shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
if (!shorthandSymbol) {
return [];
}
let shorthandDeclarations = shorthandSymbol.getDeclarations();
let shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node);
let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
return map(shorthandDeclarations,
declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
}
let result: DefinitionInfo[] = [];
let declarations = symbol.getDeclarations();
let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
let symbolKind = getSymbolKind(symbol, typeInfoResolver, node);
let containerSymbol = symbol.parent;
let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName));
});
}
return result;
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 = <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[]) {
let declarations: Declaration[] = [];
let definition: Declaration;
forEach(signatureDeclarations, d => {
if ((selectConstructors && d.kind === SyntaxKind.Constructor) ||
(!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) {
declarations.push(d);
if ((<FunctionLikeDeclaration>d).body) definition = d;
}
});
if (definition) {
result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName));
return true;
}
else if (declarations.length) {
result.push(createDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName));
return true;
}
return false;
}
}
/// Goto definition
function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
synchronizeHostData();
@ -3453,7 +3564,7 @@ module ts {
if (isJumpStatementTarget(node)) {
let labelName = (<Identifier>node).text;
let label = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>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
@ -3481,109 +3592,7 @@ module ts {
return undefined;
}
// 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.
if (symbol.flags & SymbolFlags.Alias) {
let declaration = symbol.declarations[0];
if (node.kind === SyntaxKind.Identifier && node.parent === declaration) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
}
}
// 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
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
let shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
if (!shorthandSymbol) {
return [];
}
let shorthandDeclarations = shorthandSymbol.getDeclarations();
let shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node);
let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
return map(shorthandDeclarations,
declaration => getDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
}
let result: DefinitionInfo[] = [];
let declarations = symbol.getDeclarations();
let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
let symbolKind = getSymbolKind(symbol, typeInfoResolver, node);
let containerSymbol = symbol.parent;
let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(getDefinitionInfo(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 tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
let declarations: Declaration[] = [];
let definition: Declaration;
forEach(signatureDeclarations, d => {
if ((selectConstructors && d.kind === SyntaxKind.Constructor) ||
(!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) {
declarations.push(d);
if ((<FunctionLikeDeclaration>d).body) definition = d;
}
});
if (definition) {
result.push(getDefinitionInfo(definition, symbolKind, symbolName, containerName));
return true;
}
else if (declarations.length) {
result.push(getDefinitionInfo(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 = <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;
}
return getDefinitionInfos(node, symbol);
}
/// References and Occurrences
@ -3599,7 +3608,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 +3908,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 +4031,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 +4136,33 @@ 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 referenceSymbols = findReferencesWorker(fileName, position, findInStrings, findInComments);
return convertReferences(referenceSymbols);
}
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
return findReferences(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false);
var referenceSymbols = findReferencesWorker(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false);
return convertReferences(referenceSymbols);
}
function findReferences(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferenceEntry[] {
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
return filter(findReferencesWorker(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false), rs => !!rs.definition);
}
function findReferencesWorker(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
synchronizeHostData();
let sourceFile = getValidSourceFile(fileName);
@ -4158,14 +4185,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((<BreakOrContinueStatement>node.parent), (<Identifier>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 +4212,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 +4223,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 +4235,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 +4257,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);
}
});
}
@ -4393,8 +4422,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 +4438,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 +4491,9 @@ module ts {
searchMeaning: SemanticMeaning,
findInStrings: boolean,
findInComments: boolean,
result: ReferenceEntry[]): void {
result: ReferencedSymbol[],
symbolToIndex: number[]): void {
let sourceFile = container.getSourceFile();
let tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</
@ -4473,9 +4514,12 @@ module ts {
if ((findInStrings && isInString(position)) ||
(findInComments && isInComment(position))) {
result.push({
fileName: sourceFile.fileName,
textSpan: createTextSpan(position, searchText.length),
isWriteAccess: false
definition: undefined,
references: [{
fileName: sourceFile.fileName,
textSpan: createTextSpan(position, searchText.length),
isWriteAccess: false
}]
});
}
return;
@ -4489,8 +4533,11 @@ module ts {
if (referenceSymbol) {
let referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
if (isRelatableToSearchSet(searchSymbols, referenceSymbol, referenceLocation)) {
result.push(getReferenceEntryFromNode(referenceLocation));
var relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation);
if (relatedSymbol) {
var referencedSymbol = getReferencedSymbol(relatedSymbol);
referencedSymbol.references.push(getReferenceEntryFromNode(referenceLocation));
}
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
* has two meaning : property name and property value. Therefore when we do findAllReference at the position where
@ -4499,12 +4546,31 @@ module ts {
* position of property accessing, the referenceEntry of such position will be handled in the first case.
*/
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 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: getDefinitionInfos(node, symbol)[0],
references: []
});
}
return result[index];
}
function isInString(position: number) {
let token = getTokenAtPosition(sourceFile, position);
return token && token.kind === SyntaxKind.StringLiteral && position > token.getStart();
@ -4532,7 +4598,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 +4621,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 +4640,16 @@ 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 definitions = getDefinitionInfos(superKeyword, searchSpaceNode.symbol);
var definition = definitions[0];
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 +4684,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 +4832,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 +4851,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 +4860,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 +4868,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 +5827,7 @@ module ts {
getQuickInfoAtPosition,
getDefinitionAtPosition,
getReferencesAtPosition,
findReferences,
getOccurrencesAtPosition,
getNameOrDottedNameSpan,
getBreakpointStatementAtPosition,

View File

@ -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: <encoded>; references: <encoded>[] }[]
*/
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 + ")",

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -13,4 +13,4 @@ goTo.marker('1');
verify.referencesCountIs(3);
goTo.marker('2');
verify.referencesCountIs(1);
verify.referencesCountIs(0);

View File

@ -17,4 +17,4 @@
// "any" should not be highlighted
goTo.marker();
verify.occurrencesAtPositionCount(1);
verify.occurrencesAtPositionCount(0);

View File

@ -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:

View File

@ -143,5 +143,5 @@
test.markers().forEach(m => {
goTo.position(m.position, m.fileName)
verify.occurrencesAtPositionCount(1);
verify.occurrencesAtPositionCount(0);
});

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -6,4 +6,4 @@
////a[/*1*/"blah"];
goTo.marker("1");
verify.referencesCountIs(1);
verify.referencesCountIs(0);

View File

@ -9,4 +9,4 @@
////}
goTo.marker("1");
verify.referencesCountIs(1);
verify.referencesCountIs(0);