// 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. /// 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 = (firstSymbol); if (containerForFirstSymbol.getInstanceSymbol()) { firstSymbol = containerForFirstSymbol.getInstanceSymbol(); } } if (!secondSymbol.isAlias() && secondSymbol.isContainer()) { var containerForSecondSymbol = (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 = firstSymbol.getContainer(); var t2 = 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 = (firstSymbol).getGetter(); var setterSymbol = (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 = (secondSymbol).getGetter(); var setterSymbol = (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; } } }