TypeScript/src/services/findReferenceHelpers.ts
2014-08-07 21:08:38 +02:00

152 lines
7.6 KiB
TypeScript

// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='references.ts' />
module TypeScript.Services {
export class FindReferenceHelpers {
public static compareSymbolsForLexicalIdentity(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
// Unwrap modules so that we're always referring to the variable.
if (!firstSymbol.isAlias() && firstSymbol.isContainer()) {
var containerForFirstSymbol = (<TypeScript.PullContainerSymbol>firstSymbol);
if (containerForFirstSymbol.getInstanceSymbol()) {
firstSymbol = containerForFirstSymbol.getInstanceSymbol();
}
}
if (!secondSymbol.isAlias() && secondSymbol.isContainer()) {
var containerForSecondSymbol = (<TypeScript.PullContainerSymbol>secondSymbol);
if (containerForSecondSymbol.getInstanceSymbol()) {
secondSymbol = containerForSecondSymbol.getInstanceSymbol();
}
}
if (firstSymbol.kind === secondSymbol.kind) {
if (firstSymbol === secondSymbol) {
return true;
}
// If we have two variables and they have the same name and the same parent, then
// they are the same symbol.
if (firstSymbol.kind === TypeScript.PullElementKind.Variable &&
firstSymbol.name === secondSymbol.name &&
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
return firstSymbolDecl.getParentDecl() === secondSymbolDecl.getParentDecl();
}
// If we have two properties that belong to an object literal, then we need ot see
// if they came from teh same object literal ast.
if (firstSymbol.kind === TypeScript.PullElementKind.Property &&
firstSymbol.name === secondSymbol.name &&
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
var firstParentDecl = firstSymbolDecl.getParentDecl();
var secondParentDecl = secondSymbolDecl.getParentDecl();
if (firstParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral &&
secondParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral) {
return firstParentDecl.ast() === secondParentDecl.ast();
}
}
// check if we are dealing with the implementation of interface method or a method override
if (firstSymbol.name === secondSymbol.name) {
// at this point firstSymbol.kind === secondSymbol.kind so we can pick any of those
switch (firstSymbol.kind) {
case PullElementKind.Property:
case PullElementKind.Method:
case PullElementKind.GetAccessor:
case PullElementKind.SetAccessor:
// these kinds can only be defined in types
var t1 = <PullTypeSymbol>firstSymbol.getContainer();
var t2 = <PullTypeSymbol>secondSymbol.getContainer();
t1._resolveDeclaredSymbol();
t2._resolveDeclaredSymbol();
return t1.hasBase(t2) || t2.hasBase(t1);
break;
}
}
return false;
}
else {
switch (firstSymbol.kind) {
case TypeScript.PullElementKind.Class: {
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
}
case TypeScript.PullElementKind.Property: {
if (firstSymbol.isAccessor()) {
var getterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getGetter();
var setterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getSetter();
if (getterSymbol && getterSymbol === secondSymbol) {
return true;
}
if (setterSymbol && setterSymbol === secondSymbol) {
return true;
}
}
return false;
}
case TypeScript.PullElementKind.Function: {
if (secondSymbol.isAccessor()) {
var getterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getGetter();
var setterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getSetter();
if (getterSymbol && getterSymbol === firstSymbol) {
return true;
}
if (setterSymbol && setterSymbol === firstSymbol) {
return true;
}
}
return false;
}
case TypeScript.PullElementKind.ConstructorMethod: {
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
}
}
}
return firstSymbol === secondSymbol;
}
private static checkSymbolsForDeclarationEquality(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
var firstSymbolDeclarations: TypeScript.PullDecl[] = firstSymbol.getDeclarations();
var secondSymbolDeclarations: TypeScript.PullDecl[] = secondSymbol.getDeclarations();
for (var i = 0, iLen = firstSymbolDeclarations.length; i < iLen; i++) {
for (var j = 0, jLen = secondSymbolDeclarations.length; j < jLen; j++) {
if (this.declarationsAreSameOrParents(firstSymbolDeclarations[i], secondSymbolDeclarations[j])) {
return true;
}
}
}
return false;
}
private static declarationsAreSameOrParents(firstDecl: TypeScript.PullDecl, secondDecl: TypeScript.PullDecl): boolean {
var firstParent: TypeScript.PullDecl = firstDecl.getParentDecl();
var secondParent: TypeScript.PullDecl = secondDecl.getParentDecl();
if (firstDecl === secondDecl ||
firstDecl === secondParent ||
firstParent === secondDecl ||
firstParent === secondParent) {
return true;
}
return false;
}
}
}