1/* @internal */ 2namespace ts.CallHierarchy { 3 export type NamedExpression = 4 | ClassExpression & { name: Identifier } 5 | FunctionExpression & { name: Identifier } 6 ; 7 8 /** Indictates whether a node is named function or class expression. */ 9 function isNamedExpression(node: Node): node is NamedExpression { 10 return (isFunctionExpression(node) || isClassExpression(node)) && isNamedDeclaration(node); 11 } 12 13 export type ConstNamedExpression = 14 | ClassExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } } 15 | FunctionExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } } 16 | ArrowFunction & { name: undefined, parent: VariableDeclaration & { name: Identifier } } 17 ; 18 19 /** Indicates whether a node is a function, arrow, or class expression assigned to a constant variable. */ 20 function isConstNamedExpression(node: Node): node is ConstNamedExpression { 21 return (isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node)) 22 && isVariableDeclaration(node.parent) 23 && node === node.parent.initializer 24 && isIdentifier(node.parent.name) 25 && !!(getCombinedNodeFlags(node.parent) & NodeFlags.Const); 26 } 27 28 export type CallHierarchyDeclaration = 29 | SourceFile 30 | ModuleDeclaration & { name: Identifier } 31 | FunctionDeclaration 32 | ClassDeclaration 33 | ClassStaticBlockDeclaration 34 | StructDeclaration 35 | MethodDeclaration 36 | GetAccessorDeclaration 37 | SetAccessorDeclaration 38 | NamedExpression 39 | ConstNamedExpression 40 ; 41 42 /** 43 * Indicates whether a node could possibly be a call hierarchy declaration. 44 * 45 * See `resolveCallHierarchyDeclaration` for the specific rules. 46 */ 47 function isPossibleCallHierarchyDeclaration(node: Node) { 48 return isSourceFile(node) 49 || isModuleDeclaration(node) 50 || isFunctionDeclaration(node) 51 || isFunctionExpression(node) 52 || isClassDeclaration(node) 53 || isClassExpression(node) 54 || isClassStaticBlockDeclaration(node) 55 || isMethodDeclaration(node) 56 || isMethodSignature(node) 57 || isGetAccessorDeclaration(node) 58 || isSetAccessorDeclaration(node); 59 } 60 61 /** 62 * Indicates whether a node is a valid a call hierarchy declaration. 63 * 64 * See `resolveCallHierarchyDeclaration` for the specific rules. 65 */ 66 function isValidCallHierarchyDeclaration(node: Node): node is CallHierarchyDeclaration { 67 return isSourceFile(node) 68 || isModuleDeclaration(node) && isIdentifier(node.name) 69 || isFunctionDeclaration(node) 70 || isClassDeclaration(node) 71 || isClassStaticBlockDeclaration(node) 72 || isMethodDeclaration(node) 73 || isMethodSignature(node) 74 || isGetAccessorDeclaration(node) 75 || isSetAccessorDeclaration(node) 76 || isNamedExpression(node) 77 || isConstNamedExpression(node); 78 } 79 80 /** Gets the node that can be used as a reference to a call hierarchy declaration. */ 81 function getCallHierarchyDeclarationReferenceNode(node: Exclude<CallHierarchyDeclaration, ClassStaticBlockDeclaration>) { 82 if (isSourceFile(node)) return node; 83 if (isNamedDeclaration(node)) return node.name; 84 if (isConstNamedExpression(node)) return node.parent.name; 85 return Debug.checkDefined(node.modifiers && find(node.modifiers, isDefaultModifier)); 86 } 87 88 function isDefaultModifier(node: Node) { 89 return node.kind === SyntaxKind.DefaultKeyword; 90 } 91 92 /** Gets the symbol for a call hierarchy declaration. */ 93 function getSymbolOfCallHierarchyDeclaration(typeChecker: TypeChecker, node: Exclude<CallHierarchyDeclaration, ClassStaticBlockDeclaration>) { 94 const location = getCallHierarchyDeclarationReferenceNode(node); 95 return location && typeChecker.getSymbolAtLocation(location); 96 } 97 98 /** Gets the text and range for the name of a call hierarchy declaration. */ 99 function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclaration): { text: string, pos: number, end: number } { 100 if (isSourceFile(node)) { 101 return { text: node.fileName, pos: 0, end: 0 }; 102 } 103 104 if ((isFunctionDeclaration(node) || isClassDeclaration(node)) && !isNamedDeclaration(node)) { 105 const defaultModifier = node.modifiers && find(node.modifiers, isDefaultModifier); 106 if (defaultModifier) { 107 return { text: "default", pos: defaultModifier.getStart(), end: defaultModifier.getEnd() }; 108 } 109 } 110 111 if (isClassStaticBlockDeclaration(node)) { 112 const sourceFile = node.getSourceFile(); 113 const pos = skipTrivia(sourceFile.text, moveRangePastModifiers(node).pos); 114 const end = pos + 6; /* "static".length */ 115 const typeChecker = program.getTypeChecker(); 116 const symbol = typeChecker.getSymbolAtLocation(node.parent); 117 const prefix = symbol ? `${typeChecker.symbolToString(symbol, node.parent)} ` : ""; 118 return { text: `${prefix}static {}`, pos, end }; 119 } 120 121 const declName = isConstNamedExpression(node) ? node.parent.name : 122 Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name"); 123 124 let text = 125 isIdentifier(declName) ? idText(declName) : 126 isStringOrNumericLiteralLike(declName) ? declName.text : 127 isComputedPropertyName(declName) ? 128 isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text : 129 undefined : 130 undefined; 131 if (text === undefined) { 132 const typeChecker = program.getTypeChecker(); 133 const symbol = typeChecker.getSymbolAtLocation(declName); 134 if (symbol) { 135 text = typeChecker.symbolToString(symbol, node); 136 } 137 } 138 if (text === undefined) { 139 // get the text from printing the node on a single line without comments... 140 const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); 141 text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); 142 } 143 return { text, pos: declName.getStart(), end: declName.getEnd() }; 144 } 145 146 function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): string | undefined { 147 if (isConstNamedExpression(node)) { 148 if (isModuleBlock(node.parent.parent.parent.parent) && isIdentifier(node.parent.parent.parent.parent.parent.name)) { 149 return node.parent.parent.parent.parent.parent.name.getText(); 150 } 151 return; 152 } 153 154 switch (node.kind) { 155 case SyntaxKind.GetAccessor: 156 case SyntaxKind.SetAccessor: 157 case SyntaxKind.MethodDeclaration: 158 if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { 159 return getAssignedName(node.parent)?.getText(); 160 } 161 return getNameOfDeclaration(node.parent)?.getText(); 162 case SyntaxKind.FunctionDeclaration: 163 case SyntaxKind.ClassDeclaration: 164 case SyntaxKind.StructDeclaration: 165 case SyntaxKind.ModuleDeclaration: 166 if (isModuleBlock(node.parent) && isIdentifier(node.parent.parent.name)) { 167 return node.parent.parent.name.getText(); 168 } 169 } 170 } 171 172 /** Finds the implementation of a function-like declaration, if one exists. */ 173 function findImplementation(typeChecker: TypeChecker, node: Extract<CallHierarchyDeclaration, FunctionLikeDeclaration>): Extract<CallHierarchyDeclaration, FunctionLikeDeclaration> | undefined; 174 function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined; 175 function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined { 176 if (node.body) { 177 return node; 178 } 179 if (isConstructorDeclaration(node)) { 180 return getFirstConstructorWithBody(node.parent); 181 } 182 if (isFunctionDeclaration(node) || isMethodDeclaration(node)) { 183 const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); 184 if (symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.body) { 185 return symbol.valueDeclaration; 186 } 187 return undefined; 188 } 189 return node; 190 } 191 192 function findAllInitialDeclarations(typeChecker: TypeChecker, node: Exclude<CallHierarchyDeclaration, ClassStaticBlockDeclaration>) { 193 const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); 194 let declarations: CallHierarchyDeclaration[] | undefined; 195 if (symbol && symbol.declarations) { 196 const indices = indicesOf(symbol.declarations); 197 const keys = map(symbol.declarations, decl => ({ file: decl.getSourceFile().fileName, pos: decl.pos })); 198 indices.sort((a, b) => compareStringsCaseSensitive(keys[a].file, keys[b].file) || keys[a].pos - keys[b].pos); 199 const sortedDeclarations = map(indices, i => symbol.declarations![i]); 200 let lastDecl: CallHierarchyDeclaration | undefined; 201 for (const decl of sortedDeclarations) { 202 if (isValidCallHierarchyDeclaration(decl)) { 203 if (!lastDecl || lastDecl.parent !== decl.parent || lastDecl.end !== decl.pos) { 204 declarations = append(declarations, decl); 205 } 206 lastDecl = decl; 207 } 208 } 209 } 210 return declarations; 211 } 212 213 /** Find the implementation or the first declaration for a call hierarchy declaration. */ 214 function findImplementationOrAllInitialDeclarations(typeChecker: TypeChecker, node: CallHierarchyDeclaration): CallHierarchyDeclaration | CallHierarchyDeclaration[] { 215 if (isClassStaticBlockDeclaration(node)) { 216 return node; 217 } 218 if (isFunctionLikeDeclaration(node)) { 219 return findImplementation(typeChecker, node) ?? 220 findAllInitialDeclarations(typeChecker, node) ?? 221 node; 222 } 223 return findAllInitialDeclarations(typeChecker, node) ?? node; 224 } 225 226 /** Resolves the call hierarchy declaration for a node. */ 227 export function resolveCallHierarchyDeclaration(program: Program, location: Node): CallHierarchyDeclaration | CallHierarchyDeclaration[] | undefined { 228 // A call hierarchy item must refer to either a SourceFile, Module Declaration, Class Static Block, or something intrinsically callable that has a name: 229 // - Class Declarations 230 // - Class Expressions (with a name) 231 // - Function Declarations 232 // - Function Expressions (with a name or assigned to a const variable) 233 // - Arrow Functions (assigned to a const variable) 234 // - Constructors 235 // - Class `static {}` initializer blocks 236 // - Methods 237 // - Accessors 238 // 239 // If a call is contained in a non-named callable Node (function expression, arrow function, etc.), then 240 // its containing `CallHierarchyItem` is a containing function or SourceFile that matches the above list. 241 242 const typeChecker = program.getTypeChecker(); 243 let followingSymbol = false; 244 while (true) { 245 if (isValidCallHierarchyDeclaration(location)) { 246 return findImplementationOrAllInitialDeclarations(typeChecker, location); 247 } 248 if (isPossibleCallHierarchyDeclaration(location)) { 249 const ancestor = findAncestor(location, isValidCallHierarchyDeclaration); 250 return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor); 251 } 252 if (isDeclarationName(location)) { 253 if (isValidCallHierarchyDeclaration(location.parent)) { 254 return findImplementationOrAllInitialDeclarations(typeChecker, location.parent); 255 } 256 if (isPossibleCallHierarchyDeclaration(location.parent)) { 257 const ancestor = findAncestor(location.parent, isValidCallHierarchyDeclaration); 258 return ancestor && findImplementationOrAllInitialDeclarations(typeChecker, ancestor); 259 } 260 if (isVariableDeclaration(location.parent) && location.parent.initializer && isConstNamedExpression(location.parent.initializer)) { 261 return location.parent.initializer; 262 } 263 return undefined; 264 } 265 if (isConstructorDeclaration(location)) { 266 if (isValidCallHierarchyDeclaration(location.parent)) { 267 return location.parent; 268 } 269 return undefined; 270 } 271 if (location.kind === SyntaxKind.StaticKeyword && isClassStaticBlockDeclaration(location.parent)) { 272 location = location.parent; 273 continue; 274 } 275 // #39453 276 if (isVariableDeclaration(location) && location.initializer && isConstNamedExpression(location.initializer)) { 277 return location.initializer; 278 } 279 if (!followingSymbol) { 280 let symbol = typeChecker.getSymbolAtLocation(location); 281 if (symbol) { 282 if (symbol.flags & SymbolFlags.Alias) { 283 symbol = typeChecker.getAliasedSymbol(symbol); 284 } 285 if (symbol.valueDeclaration) { 286 followingSymbol = true; 287 location = symbol.valueDeclaration; 288 continue; 289 } 290 } 291 } 292 return undefined; 293 } 294 } 295 296 /** Creates a `CallHierarchyItem` for a call hierarchy declaration. */ 297 export function createCallHierarchyItem(program: Program, node: CallHierarchyDeclaration): CallHierarchyItem { 298 const sourceFile = node.getSourceFile(); 299 const name = getCallHierarchyItemName(program, node); 300 const containerName = getCallHierarchItemContainerName(node); 301 const kind = getNodeKind(node); 302 const kindModifiers = getNodeModifiers(node); 303 const span = createTextSpanFromBounds(skipTrivia(sourceFile.text, node.getFullStart(), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), node.getEnd()); 304 const selectionSpan = createTextSpanFromBounds(name.pos, name.end); 305 return { file: sourceFile.fileName, kind, kindModifiers, name: name.text, containerName, span, selectionSpan }; 306 } 307 308 function isDefined<T>(x: T): x is NonNullable<T> { 309 return x !== undefined; 310 } 311 312 interface CallSite { 313 declaration: CallHierarchyDeclaration; 314 range: TextRange; 315 } 316 317 function convertEntryToCallSite(entry: FindAllReferences.Entry): CallSite | undefined { 318 if (entry.kind === FindAllReferences.EntryKind.Node) { 319 const { node } = entry; 320 if (isCallOrNewExpressionTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) 321 || isTaggedTemplateTag(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) 322 || isDecoratorTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) 323 || isJsxOpeningLikeElementTagName(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true) 324 || isRightSideOfPropertyAccess(node) 325 || isArgumentExpressionOfElementAccess(node)) { 326 const sourceFile = node.getSourceFile(); 327 const ancestor = findAncestor(node, isValidCallHierarchyDeclaration) || sourceFile; 328 return { declaration: ancestor, range: createTextRangeFromNode(node, sourceFile) }; 329 } 330 } 331 } 332 333 function getCallSiteGroupKey(entry: CallSite) { 334 return getNodeId(entry.declaration); 335 } 336 337 function createCallHierarchyIncomingCall(from: CallHierarchyItem, fromSpans: TextSpan[]): CallHierarchyIncomingCall { 338 return { from, fromSpans }; 339 } 340 341 function convertCallSiteGroupToIncomingCall(program: Program, entries: readonly CallSite[]) { 342 return createCallHierarchyIncomingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range))); 343 } 344 345 /** Gets the call sites that call into the provided call hierarchy declaration. */ 346 export function getIncomingCalls(program: Program, declaration: CallHierarchyDeclaration, cancellationToken: CancellationToken): CallHierarchyIncomingCall[] { 347 // Source files and modules have no incoming calls. 348 if (isSourceFile(declaration) || isModuleDeclaration(declaration) || isClassStaticBlockDeclaration(declaration)) { 349 return []; 350 } 351 const location = getCallHierarchyDeclarationReferenceNode(declaration); 352 const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, { use: FindAllReferences.FindReferencesUse.References }, convertEntryToCallSite), isDefined); 353 return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : []; 354 } 355 356 function createCallSiteCollector(program: Program, callSites: CallSite[]): (node: Node | undefined) => void { 357 function recordCallSite(node: CallExpression | NewExpression | TaggedTemplateExpression | PropertyAccessExpression | ElementAccessExpression | Decorator | JsxOpeningLikeElement | ClassStaticBlockDeclaration) { 358 const target = 359 isTaggedTemplateExpression(node) ? node.tag : 360 isJsxOpeningLikeElement(node) ? node.tagName : 361 isAccessExpression(node) ? node : 362 isClassStaticBlockDeclaration(node) ? node : 363 node.expression; 364 const declaration = resolveCallHierarchyDeclaration(program, target); 365 if (declaration) { 366 const range = createTextRangeFromNode(target, node.getSourceFile()); 367 if (isArray(declaration)) { 368 for (const decl of declaration) { 369 callSites.push({ declaration: decl, range }); 370 } 371 } 372 else { 373 callSites.push({ declaration, range }); 374 } 375 } 376 } 377 378 function collect(node: Node | undefined) { 379 if (!node) return; 380 if (node.flags & NodeFlags.Ambient) { 381 // do not descend into ambient nodes. 382 return; 383 } 384 385 if (isValidCallHierarchyDeclaration(node)) { 386 // do not descend into other call site declarations, other than class member names 387 if (isClassLike(node)) { 388 for (const member of node.members) { 389 if (member.name && isComputedPropertyName(member.name)) { 390 collect(member.name.expression); 391 } 392 } 393 } 394 return; 395 } 396 397 switch (node.kind) { 398 case SyntaxKind.Identifier: 399 case SyntaxKind.ImportEqualsDeclaration: 400 case SyntaxKind.ImportDeclaration: 401 case SyntaxKind.ExportDeclaration: 402 case SyntaxKind.InterfaceDeclaration: 403 case SyntaxKind.TypeAliasDeclaration: 404 // do not descend into nodes that cannot contain callable nodes 405 return; 406 case SyntaxKind.ClassStaticBlockDeclaration: 407 recordCallSite(node as ClassStaticBlockDeclaration); 408 return; 409 case SyntaxKind.TypeAssertionExpression: 410 case SyntaxKind.AsExpression: 411 // do not descend into the type side of an assertion 412 collect((node as TypeAssertion | AsExpression).expression); 413 return; 414 case SyntaxKind.VariableDeclaration: 415 case SyntaxKind.Parameter: 416 // do not descend into the type of a variable or parameter declaration 417 collect((node as VariableDeclaration | ParameterDeclaration).name); 418 collect((node as VariableDeclaration | ParameterDeclaration).initializer); 419 return; 420 case SyntaxKind.CallExpression: 421 // do not descend into the type arguments of a call expression 422 recordCallSite(node as CallExpression); 423 collect((node as CallExpression).expression); 424 forEach((node as CallExpression).arguments, collect); 425 return; 426 case SyntaxKind.NewExpression: 427 // do not descend into the type arguments of a new expression 428 recordCallSite(node as NewExpression); 429 collect((node as NewExpression).expression); 430 forEach((node as NewExpression).arguments, collect); 431 return; 432 case SyntaxKind.TaggedTemplateExpression: 433 // do not descend into the type arguments of a tagged template expression 434 recordCallSite(node as TaggedTemplateExpression); 435 collect((node as TaggedTemplateExpression).tag); 436 collect((node as TaggedTemplateExpression).template); 437 return; 438 case SyntaxKind.JsxOpeningElement: 439 case SyntaxKind.JsxSelfClosingElement: 440 // do not descend into the type arguments of a JsxOpeningLikeElement 441 recordCallSite(node as JsxOpeningLikeElement); 442 collect((node as JsxOpeningLikeElement).tagName); 443 collect((node as JsxOpeningLikeElement).attributes); 444 return; 445 case SyntaxKind.Decorator: 446 recordCallSite(node as Decorator); 447 collect((node as Decorator).expression); 448 return; 449 case SyntaxKind.PropertyAccessExpression: 450 case SyntaxKind.ElementAccessExpression: 451 recordCallSite(node as AccessExpression); 452 forEachChild(node, collect); 453 break; 454 case SyntaxKind.SatisfiesExpression: 455 // do not descend into the type side of an assertion 456 collect((node as SatisfiesExpression).expression); 457 return; 458 } 459 460 if (isPartOfTypeNode(node)) { 461 // do not descend into types 462 return; 463 } 464 465 forEachChild(node, collect); 466 } 467 return collect; 468 } 469 470 function collectCallSitesOfSourceFile(node: SourceFile, collect: (node: Node | undefined) => void) { 471 forEach(node.statements, collect); 472 } 473 474 function collectCallSitesOfModuleDeclaration(node: ModuleDeclaration, collect: (node: Node | undefined) => void) { 475 if (!hasSyntacticModifier(node, ModifierFlags.Ambient) && node.body && isModuleBlock(node.body)) { 476 forEach(node.body.statements, collect); 477 } 478 } 479 480 function collectCallSitesOfFunctionLikeDeclaration(typeChecker: TypeChecker, node: FunctionLikeDeclaration, collect: (node: Node | undefined) => void) { 481 const implementation = findImplementation(typeChecker, node); 482 if (implementation) { 483 forEach(implementation.parameters, collect); 484 collect(implementation.body); 485 } 486 } 487 488 function collectCallSitesOfClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, collect: (node: Node | undefined) => void) { 489 collect(node.body); 490 } 491 492 function collectCallSitesOfClassLikeDeclaration(node: ClassLikeDeclaration, collect: (node: Node | undefined) => void) { 493 forEach(node.modifiers, collect); 494 const heritage = getClassExtendsHeritageElement(node); 495 if (heritage) { 496 collect(heritage.expression); 497 } 498 for (const member of node.members) { 499 if (canHaveModifiers(member)) { 500 forEach(member.modifiers, collect); 501 } 502 if (isPropertyDeclaration(member)) { 503 collect(member.initializer); 504 } 505 else if (isConstructorDeclaration(member) && member.body) { 506 forEach(member.parameters, collect); 507 collect(member.body); 508 } 509 else if (isClassStaticBlockDeclaration(member)) { 510 collect(member); 511 } 512 } 513 } 514 515 function collectCallSites(program: Program, node: CallHierarchyDeclaration) { 516 const callSites: CallSite[] = []; 517 const collect = createCallSiteCollector(program, callSites); 518 switch (node.kind) { 519 case SyntaxKind.SourceFile: 520 collectCallSitesOfSourceFile(node, collect); 521 break; 522 case SyntaxKind.ModuleDeclaration: 523 collectCallSitesOfModuleDeclaration(node, collect); 524 break; 525 case SyntaxKind.FunctionDeclaration: 526 case SyntaxKind.FunctionExpression: 527 case SyntaxKind.ArrowFunction: 528 case SyntaxKind.MethodDeclaration: 529 case SyntaxKind.GetAccessor: 530 case SyntaxKind.SetAccessor: 531 collectCallSitesOfFunctionLikeDeclaration(program.getTypeChecker(), node, collect); 532 break; 533 case SyntaxKind.ClassDeclaration: 534 case SyntaxKind.ClassExpression: 535 case SyntaxKind.StructDeclaration: 536 collectCallSitesOfClassLikeDeclaration(node, collect); 537 break; 538 case SyntaxKind.ClassStaticBlockDeclaration: 539 collectCallSitesOfClassStaticBlockDeclaration(node, collect); 540 break; 541 default: 542 Debug.assertNever(node); 543 } 544 return callSites; 545 } 546 547 function createCallHierarchyOutgoingCall(to: CallHierarchyItem, fromSpans: TextSpan[]): CallHierarchyOutgoingCall { 548 return { to, fromSpans }; 549 } 550 551 function convertCallSiteGroupToOutgoingCall(program: Program, entries: readonly CallSite[]) { 552 return createCallHierarchyOutgoingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range))); 553 } 554 555 /** Gets the call sites that call out of the provided call hierarchy declaration. */ 556 export function getOutgoingCalls(program: Program, declaration: CallHierarchyDeclaration): CallHierarchyOutgoingCall[] { 557 if (declaration.flags & NodeFlags.Ambient || isMethodSignature(declaration)) { 558 return []; 559 } 560 return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries)); 561 } 562} 563