/// <nodoc /> public Possible <IReadOnlyList <SymbolLocation> > GetDefinitionAtPosition(INode node) { // TODO: consider special hint/message if the current node is a template expression with interpolated expressions. if (node.Kind == SyntaxKind.NoSubstitutionTemplateLiteral && node.Parent.Kind == SyntaxKind.TaggedTemplateExpression && node.Parent.Cast <ITaggedTemplateExpression>().IsWellKnownTemplateExpression(out var name)) { return(DefinitionForTemplateExpression(node, name)); } var result = GetDefinitionFromVariableDeclarationList(node); if (result.Succeeded) { return(result); } if (Utilities.IsJumpStatementTarget(node)) { var labelName = node.Cast <IIdentifier>().Text; var label = Utilities.GetTargetLabel(node.Parent, labelName); // TODO: saqadri - Port // return label ? [createDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined; return(Success(new[] { GetLocationFromNode(label, symbol: null), })); } var symbol = TypeChecker.GetSymbolAtLocation(node) ?? node.Symbol ?? node.ResolvedSymbol; // Could not find a symbol e.g. node is string or number keyword, // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol if (symbol == null) { // return null; return(SilentError()); } // 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) != SymbolFlags.None) { var declaration = symbol.Declarations.FirstOrDefault(); // Go to the original declaration for cases: // // (1) when the aliased symbol was declared in the location(parent). // (2) when the aliased symbol is originating from a named import. if (node.Kind == SyntaxKind.Identifier && declaration != null && (node.Parent.ResolveUnionType() == declaration.ResolveUnionType() || (declaration.Kind == SyntaxKind.ImportSpecifier && declaration?.Parent.Kind == SyntaxKind.NamedImports))) { symbol = TypeChecker.GetAliasedSymbol(symbol); } else if (node.Kind == SyntaxKind.Identifier && declaration?.Kind == SyntaxKind.NamespaceImport && declaration.Name != null) { return(new[] { GetLocationFromNode(declaration.Name, 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) { var shorthandSymbol = TypeChecker.GetShorthandAssignmentValueSymbol(symbol.ValueDeclaration); if (shorthandSymbol == null) { return(Success(new SymbolLocation[] { })); } var shorthandDeclaratons = shorthandSymbol.GetDeclarations(); // var shorthandSymbolKind = GetSymbolKind(shorthandSymbol, node); // var shorthandSymbolName = TypeChecker.SymbolToString(shorthandSymbol); // var shorthandContainerName = TypeChecker.SymbolToString(shorthandSymbol.Parent, node); return(Success(shorthandDeclaratons.Select( declaration => GetLocationFromNode(declaration, shorthandSymbol)).ToArray())); } if (Utilities.IsNameOfPropertyAssignment(node)) { return(GetDefinitionForPropertyAssignment(node)); } return(GetDefinitionFromSymbol(symbol, node)); }