namespace ts . FindAllReferences { export interface SymbolAndEntries { readonly definition : Definition | undefined ; readonly references : readonly Entry [ ] ; } export const enum DefinitionKind { Symbol , Label , Keyword , This , String , TripleSlashReference } export type Definition = { readonly type : DefinitionKind . Symbol ; readonly symbol : Symbol ; } | { readonly type : DefinitionKind . Label ; readonly node : Identifier ; } | { readonly type : DefinitionKind . Keyword ; readonly node : Node ; } | { readonly type : DefinitionKind . This ; readonly node : Node ; } | { readonly type : DefinitionKind . String ; readonly node : StringLiteralLike ; } | { readonly type : DefinitionKind . TripleSlashReference ; readonly reference : FileReference ; readonly file : SourceFile ; } ; export const enum EntryKind { Span , Node , StringLiteral , SearchedLocalFoundProperty , SearchedPropertyFoundLocal } export type NodeEntryKind = EntryKind . Node | EntryKind . StringLiteral | EntryKind . SearchedLocalFoundProperty | EntryKind . SearchedPropertyFoundLocal ; export type Entry = NodeEntry | SpanEntry ; export interface ContextWithStartAndEndNode { start : Node ; end : Node ; } export type ContextNode = Node | ContextWithStartAndEndNode ; export interface NodeEntry { readonly kind : NodeEntryKind ; readonly node : Node ; readonly context ? : ContextNode ; } export interface SpanEntry { readonly kind : EntryKind . Span ; readonly fileName : string ; readonly textSpan : TextSpan ; } export function nodeEntry ( node , kind = EntryKind . Node ) { return { kind , node : ( node as NamedDeclaration ) . name || node , context : getContextNodeForNodeEntry ( node ) } ; } export function isContextWithStartAndEndNode ( node ) { return node && ( node as Node ) . kind === undefined ; } function getContextNodeForNodeEntry ( node ) { if ( isDeclaration ( node ) ) { return getContextNode ( node ) ; } if ( ! node . parent ) return undefined ; if ( ! isDeclaration ( node . parent ) && ! isExportAssignment ( node . parent ) ) { if ( isInJSFile ( node ) ) { const binaryExpression = isBinaryExpression ( node . parent ) ? node . parent : isAccessExpression ( node . parent ) && isBinaryExpression ( node . parent . parent ) && node . parent . parent . left === node . parent ? node . parent . parent : undefined ; if ( binaryExpression && getAssignmentDeclarationKind ( binaryExpression ) !== AssignmentDeclarationKind . None ) { return getContextNode ( binaryExpression ) ; } } if ( isJsxOpeningElement ( node . parent ) || isJsxClosingElement ( node . parent ) ) { return node . parent . parent ; } else if ( isJsxSelfClosingElement ( node . parent ) || isLabeledStatement ( node . parent ) || isBreakOrContinueStatement ( node . parent ) ) { return node . parent ; } else if ( isStringLiteralLike ( node ) ) { const validImport = tryGetImportFromModuleSpecifier ( node ) ; if ( validImport ) { const declOrStatement = findAncestor ( validImport , node => isDeclaration ( node ) || isStatement ( node ) || isJSDocTag ( node ) ) ! as NamedDeclaration | Statement | JSDocTag ; return isDeclaration ( declOrStatement ) ? getContextNode ( declOrStatement ) : declOrStatement ; } } const propertyName = findAncestor ( node , isComputedPropertyName ) ; return propertyName ? getContextNode ( propertyName . parent ) : undefined ; } if ( node . parent . name === node || isConstructorDeclaration ( node . parent ) || isExportAssignment ( node . parent ) || ( ( isImportOrExportSpecifier ( node . parent ) || isBindingElement ( node . parent ) ) && node . parent . propertyName === node ) || ( node . kind === SyntaxKind . DefaultKeyword && hasSyntacticModifier ( node . parent , ModifierFlags . ExportDefault ) ) ) { return getContextNode ( node . parent ) ; } return undefined ; } export function getContextNode ( node ) { if ( ! node ) return undefined ; switch ( node . kind ) { case SyntaxKind . VariableDeclaration : return ! isVariableDeclarationList ( node . parent ) || node . parent . declarations . length !== 1 ? node : isVariableStatement ( node . parent . parent ) ? node . parent . parent : isForInOrOfStatement ( node . parent . parent ) ? getContextNode ( node . parent . parent ) : node . parent ; case SyntaxKind . BindingElement : return getContextNode ( node . parent . parent as NamedDeclaration ) ; case SyntaxKind . ImportSpecifier : return node . parent . parent . parent ; case SyntaxKind . ExportSpecifier : case SyntaxKind . NamespaceImport : return node . parent . parent ; case SyntaxKind . ImportClause : case SyntaxKind . NamespaceExport : return node . parent ; case SyntaxKind . BinaryExpression : return isExpressionStatement ( node . parent ) ? node . parent : node ; case SyntaxKind . ForOfStatement : case SyntaxKind . ForInStatement : return { start : ( node as ForInOrOfStatement ) . initializer , end : ( node as ForInOrOfStatement ) . expression } ; case SyntaxKind . PropertyAssignment : case SyntaxKind . ShorthandPropertyAssignment : return isArrayLiteralOrObjectLiteralDestructuringPattern ( node . parent ) ? getContextNode ( findAncestor ( node . parent , node => isBinaryExpression ( node ) || isForInOrOfStatement ( node ) ) as BinaryExpression | ForInOrOfStatement ) : node ; default : return node ; } } export function toContextSpan ( textSpan , sourceFile , context ? ) { if ( ! context ) return undefined ; const contextSpan = isContextWithStartAndEndNode ( context ) ? getTextSpan ( context . start , sourceFile , context . end ) : getTextSpan ( context , sourceFile ) ; return contextSpan . start !== textSpan . start || contextSpan . length !== textSpan . length ? { contextSpan } : undefined ; } export const enum FindReferencesUse { /**
         * When searching for references to a symbol, the location will not be adjusted (this is the default behavior when not specified).
         */ Other , /**
         * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword.
         */ References , /**
         * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword.
         * Unlike `References`, the location will only be adjusted keyword belonged to a declaration with a valid name.
         * If set, we will find fewer references -- if it is referenced by several different names, we still only find references for the original name.
         */ Rename } export interface Options { readonly findInStrings ? : boolean ; readonly findInComments ? : boolean ; readonly use ? : FindReferencesUse ; /** True if we are searching for implementations. We will have a different method of adding references if so. */ readonly implementations ? : boolean ; /**
         * True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
         * The options controls the behavior for the whole rename operation; it cannot be changed on a per-file basis.
         * Default is false for backwards compatibility.
         */ readonly providePrefixAndSuffixTextForRename ? : boolean ; } export function findReferencedSymbols ( program , cancellationToken , sourceFiles , sourceFile , position ) { const node = getTouchingPropertyName ( sourceFile , position ) ; const referencedSymbols = Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , { use : FindReferencesUse . References } ) ; const checker = program . getTypeChecker ( ) ; const symbol = checker . getSymbolAtLocation ( node ) ; return ! referencedSymbols || ! referencedSymbols . length ? undefined : mapDefined < SymbolAndEntries , ReferencedSymbol > ( referencedSymbols , ( { definition , references } ) => definition && { definition : checker . runWithCancellationToken ( cancellationToken , checker => definitionToReferencedSymbolDefinitionInfo ( definition , checker , node ) ) , references : references . map ( r => toReferenceEntry ( r , symbol ) ) } ) ; } export function getImplementationsAtPosition ( program , cancellationToken , sourceFiles , sourceFile , position ) { const node = getTouchingPropertyName ( sourceFile , position ) ; let referenceEntries ; const entries = getImplementationReferenceEntries ( program , cancellationToken , sourceFiles , node , position ) ; if ( node . parent . kind === SyntaxKind . PropertyAccessExpression || node . parent . kind === SyntaxKind . BindingElement || node . parent . kind === SyntaxKind . ElementAccessExpression || node . kind === SyntaxKind . SuperKeyword ) { referenceEntries = entries && [ ... entries ] ; } else { const queue = entries && [ ... entries ] ; const seenNodes = new Map < number , true > ( ) ; while ( queue && queue . length ) { const entry = queue . shift ( ) as NodeEntry ; if ( ! addToSeen ( seenNodes , getNodeId ( entry . node ) ) ) { continue ; } referenceEntries = append ( referenceEntries , entry ) ; const entries = getImplementationReferenceEntries ( program , cancellationToken , sourceFiles , entry . node , entry . node . pos ) ; if ( entries ) { queue . push ( ... entries ) ; } } } const checker = program . getTypeChecker ( ) ; return map ( referenceEntries , entry => toImplementationLocation ( entry , checker ) ) ; } function getImplementationReferenceEntries ( program , cancellationToken , sourceFiles , node , position ) { if ( node . kind === SyntaxKind . SourceFile ) { return undefined ; } const checker = program . getTypeChecker ( ) ; if ( node . parent . kind === SyntaxKind . ShorthandPropertyAssignment ) { const result = [ ] ; Core . getReferenceEntriesForShorthandPropertyAssignment ( node , checker , node => result . push ( nodeEntry ( node ) ) ) ; return result ; } else if ( node . kind === SyntaxKind . SuperKeyword || isSuperProperty ( node . parent ) ) { const symbol = checker . getSymbolAtLocation ( node ) ! ; return symbol . valueDeclaration && [ nodeEntry ( symbol . valueDeclaration ) ] ; } else { return getReferenceEntriesForNode ( position , node , program , sourceFiles , cancellationToken , { implementations : true , use : FindReferencesUse . References } ) ; } } export function findReferenceOrRenameEntries < T > ( program , cancellationToken , sourceFiles , node , position , options , convertEntry ) { return map ( flattenEntries ( Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options ) ) , entry => convertEntry ( entry , node , program . getTypeChecker ( ) ) ) ; } export type ToReferenceOrRenameEntry < T > = ( entry : Entry , originalNode : Node , checker : TypeChecker ) => T ; export function getReferenceEntriesForNode ( position , node , program , sourceFiles , cancellationToken , options = { } , sourceFilesSet = new Set ( sourceFiles . map ( f => f . fileName ) ) ) { return flattenEntries ( Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ) ; } function flattenEntries ( referenceSymbols ) { return referenceSymbols && flatMap ( referenceSymbols , r => r . references ) ; } function definitionToReferencedSymbolDefinitionInfo ( def , checker , originalNode ) { const info = ( ( ) : { sourceFile : SourceFile ; textSpan : TextSpan ; name : string ; kind : ScriptElementKind ; displayParts : SymbolDisplayPart [ ] ; context ? : Node | ContextWithStartAndEndNode ; } => { switch ( def . type ) { case DefinitionKind . Symbol : { const { symbol } = def ; const { displayParts , kind } = getDefinitionKindAndDisplayParts ( symbol , checker , originalNode ) ; const name = displayParts . map ( p => p . text ) . join ( "" ) ; const declaration = symbol . declarations && firstOrUndefined ( symbol . declarations ) ; const node = declaration ? ( getNameOfDeclaration ( declaration ) || declaration ) : originalNode ; return { ... getFileAndTextSpanFromNode ( node ) , name , kind , displayParts , context : getContextNode ( declaration ) } ; } case DefinitionKind . Label : { const { node } = def ; return { ... getFileAndTextSpanFromNode ( node ) , name : node . text , kind : ScriptElementKind . label , displayParts : [ displayPart ( node . text , SymbolDisplayPartKind . text ) ] } ; } case DefinitionKind . Keyword : { const { node } = def ; const name = tokenToString ( node . kind ) ! ; return { ... getFileAndTextSpanFromNode ( node ) , name , kind : ScriptElementKind . keyword , displayParts : [ { text : name , kind : ScriptElementKind . keyword } ] } ; } case DefinitionKind . This : { const { node } = def ; const symbol = checker . getSymbolAtLocation ( node ) ; const displayParts = symbol && SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( checker , symbol , node . getSourceFile ( ) , getContainerNode ( node ) , node ) . displayParts || [ textPart ( "this" ) ] ; return { ... getFileAndTextSpanFromNode ( node ) , name : "this" , kind : ScriptElementKind . variableElement , displayParts } ; } case DefinitionKind . String : { const { node } = def ; return { ... getFileAndTextSpanFromNode ( node ) , name : node . text , kind : ScriptElementKind . variableElement , displayParts : [ displayPart ( getTextOfNode ( node ) , SymbolDisplayPartKind . stringLiteral ) ] } ; } case DefinitionKind . TripleSlashReference : { return { textSpan : createTextSpanFromRange ( def . reference ) , sourceFile : def . file , name : def . reference . fileName , kind : ScriptElementKind . string , displayParts : [ displayPart ( `"${ def . reference . fileName }"` , SymbolDisplayPartKind . stringLiteral ) ] } ; } default : return Debug . assertNever ( def ) ; } } ) ( ) ; const { sourceFile , textSpan , name , kind , displayParts , context } = info ; return { containerKind : ScriptElementKind . unknown , containerName : "" , fileName : sourceFile . fileName , kind , name , textSpan , displayParts , ... toContextSpan ( textSpan , sourceFile , context ) } ; } function getFileAndTextSpanFromNode ( node ) { const sourceFile = node . getSourceFile ( ) ; return { sourceFile , textSpan : getTextSpan ( isComputedPropertyName ( node ) ? node . expression : node , sourceFile ) } ; } function getDefinitionKindAndDisplayParts ( symbol , checker , node ) { const meaning = Core . getIntersectingMeaningFromDeclarations ( node , symbol ) ; const enclosingDeclaration = symbol . declarations && firstOrUndefined ( symbol . declarations ) || node ; const { displayParts , symbolKind } = SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( checker , symbol , enclosingDeclaration . getSourceFile ( ) , enclosingDeclaration , enclosingDeclaration , meaning ) ; return { displayParts , kind : symbolKind } ; } export function toRenameLocation ( entry , originalNode , checker , providePrefixAndSuffixText ) { return { ... entryToDocumentSpan ( entry ) , ... ( providePrefixAndSuffixText && getPrefixAndSuffixText ( entry , originalNode , checker ) ) } ; } export function toReferenceEntry ( entry , symbol ) { const documentSpan = entryToDocumentSpan ( entry ) ; if ( entry . kind === EntryKind . Span ) { return { ... documentSpan , isWriteAccess : false , isDefinition : false } ; } const { kind , node } = entry ; return { ... documentSpan , isWriteAccess : isWriteAccessForReference ( node ) , isDefinition : isDeclarationOfSymbol ( node , symbol ) , isInString : kind === EntryKind . StringLiteral ? true : undefined , } ; } function entryToDocumentSpan ( entry ) { if ( entry . kind === EntryKind . Span ) { return { textSpan : entry . textSpan , fileName : entry . fileName } ; } else { const sourceFile = entry . node . getSourceFile ( ) ; const textSpan = getTextSpan ( entry . node , sourceFile ) ; return { textSpan , fileName : sourceFile . fileName , ... toContextSpan ( textSpan , sourceFile , entry . context ) } ; } } interface PrefixAndSuffix { readonly prefixText ? : string ; readonly suffixText ? : string ; } function getPrefixAndSuffixText ( entry , originalNode , checker ) { if ( entry . kind !== EntryKind . Span && isIdentifier ( originalNode ) ) { const { node , kind } = entry ; const parent = node . parent ; const name = originalNode . text ; const isShorthandAssignment = isShorthandPropertyAssignment ( parent ) ; if ( isShorthandAssignment || ( isObjectBindingElementWithoutPropertyName ( parent ) && parent . name === node && parent . dotDotDotToken === undefined ) ) { const prefixColon = { prefixText : name + ": " } ; const suffixColon = { suffixText : ": " + name } ; if ( kind === EntryKind . SearchedLocalFoundProperty ) { return prefixColon ; } if ( kind === EntryKind . SearchedPropertyFoundLocal ) { return suffixColon ; } if ( isShorthandAssignment ) { const grandParent = parent . parent ; if ( isObjectLiteralExpression ( grandParent ) && isBinaryExpression ( grandParent . parent ) && isModuleExportsAccessExpression ( grandParent . parent . left ) ) { return prefixColon ; } return suffixColon ; } else { return prefixColon ; } } else if ( isImportSpecifier ( parent ) && ! parent . propertyName ) { const originalSymbol = isExportSpecifier ( originalNode . parent ) ? checker . getExportSpecifierLocalTargetSymbol ( originalNode . parent ) : checker . getSymbolAtLocation ( originalNode ) ; return contains ( originalSymbol ! . declarations , parent ) ? { prefixText : name + " as " } : emptyOptions ; } else if ( isExportSpecifier ( parent ) && ! parent . propertyName ) { return originalNode === entry . node || checker . getSymbolAtLocation ( originalNode ) === checker . getSymbolAtLocation ( entry . node ) ? { prefixText : name + " as " } : { suffixText : " as " + name } ; } } return emptyOptions ; } function toImplementationLocation ( entry , checker ) { const documentSpan = entryToDocumentSpan ( entry ) ; if ( entry . kind !== EntryKind . Span ) { const { node } = entry ; return { ... documentSpan , ... implementationKindDisplayParts ( node , checker ) } ; } else { return { ... documentSpan , kind : ScriptElementKind . unknown , displayParts : [ ] } ; } } function implementationKindDisplayParts ( node , checker ) { const symbol = checker . getSymbolAtLocation ( isDeclaration ( node ) && node . name ? node . name : node ) ; if ( symbol ) { return getDefinitionKindAndDisplayParts ( symbol , checker , node ) ; } else if ( node . kind === SyntaxKind . ObjectLiteralExpression ) { return { kind : ScriptElementKind . interfaceElement , displayParts : [ punctuationPart ( SyntaxKind . OpenParenToken ) , textPart ( "object literal" ) , punctuationPart ( SyntaxKind . CloseParenToken ) ] } ; } else if ( node . kind === SyntaxKind . ClassExpression ) { return { kind : ScriptElementKind . localClassElement , displayParts : [ punctuationPart ( SyntaxKind . OpenParenToken ) , textPart ( "anonymous local class" ) , punctuationPart ( SyntaxKind . CloseParenToken ) ] } ; } else { return { kind : getNodeKind ( node ) , displayParts : [ ] } ; } } export function toHighlightSpan ( entry ) { const documentSpan = entryToDocumentSpan ( entry ) ; if ( entry . kind === EntryKind . Span ) { return { fileName : documentSpan . fileName , span : { textSpan : documentSpan . textSpan , kind : HighlightSpanKind . reference } } ; } const writeAccess = isWriteAccessForReference ( entry . node ) ; const span = { textSpan : documentSpan . textSpan , kind : writeAccess ? HighlightSpanKind . writtenReference : HighlightSpanKind . reference , isInString : entry . kind === EntryKind . StringLiteral ? true : undefined , ... documentSpan . contextSpan && { contextSpan : documentSpan . contextSpan } } ; return { fileName : documentSpan . fileName , span } ; } function getTextSpan ( node , sourceFile , endNode ? ) { let start = node . getStart ( sourceFile ) ; let end = ( endNode || node ) . getEnd ( ) ; if ( isStringLiteralLike ( node ) ) { Debug . assert ( endNode === undefined ) ; start += 1 ; end -= 1 ; } return createTextSpanFromBounds ( start , end ) ; } export function getTextSpanOfEntry ( entry ) { return entry . kind === EntryKind . Span ? entry . textSpan : getTextSpan ( entry . node , entry . node . getSourceFile ( ) ) ; } /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */ function isWriteAccessForReference ( node ) { const decl = getDeclarationFromName ( node ) ; return ! ! decl && declarationIsWriteAccess ( decl ) || node . kind === SyntaxKind . DefaultKeyword || isWriteAccess ( node ) ; } /** Whether a reference, `node`, is a definition of the `target` symbol */ function isDeclarationOfSymbol ( node , target ) { if ( ! target ) return false ; const source = getDeclarationFromName ( node ) || ( node . kind === SyntaxKind . DefaultKeyword ? node . parent : isLiteralComputedPropertyDeclarationName ( node ) ? node . parent . parent : node . kind === SyntaxKind . ConstructorKeyword && isConstructorDeclaration ( node . parent ) ? node . parent . parent : undefined ) ; const commonjsSource = source && isBinaryExpression ( source ) ? source . left as unknown as Declaration : undefined ; return ! ! ( source && target . declarations ?. some ( d => d === source || d === commonjsSource ) ) ; } /**
     * True if 'decl' provides a value, as in `function f() {}`;
     * false if 'decl' is just a location for a future write, as in 'let x;'
     */ function declarationIsWriteAccess ( decl ) { if ( ! ! ( decl . flags & NodeFlags . Ambient ) ) return true ; switch ( decl . kind ) { case SyntaxKind . BinaryExpression : case SyntaxKind . BindingElement : case SyntaxKind . ClassDeclaration : case SyntaxKind . ClassExpression : case SyntaxKind . DefaultKeyword : case SyntaxKind . EnumDeclaration : case SyntaxKind . EnumMember : case SyntaxKind . ExportSpecifier : case SyntaxKind . ImportClause : case SyntaxKind . ImportEqualsDeclaration : case SyntaxKind . ImportSpecifier : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . JSDocCallbackTag : case SyntaxKind . JSDocTypedefTag : case SyntaxKind . JsxAttribute : case SyntaxKind . ModuleDeclaration : case SyntaxKind . NamespaceExportDeclaration : case SyntaxKind . NamespaceImport : case SyntaxKind . NamespaceExport : case SyntaxKind . Parameter : case SyntaxKind . ShorthandPropertyAssignment : case SyntaxKind . TypeAliasDeclaration : case SyntaxKind . TypeParameter : return true ; case SyntaxKind . PropertyAssignment : return ! isArrayLiteralOrObjectLiteralDestructuringPattern ( ( decl as PropertyAssignment ) . parent ) ; case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . Constructor : case SyntaxKind . MethodDeclaration : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : return ! ! ( decl as FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration ) . body ; case SyntaxKind . VariableDeclaration : case SyntaxKind . PropertyDeclaration : return ! ! ( decl as VariableDeclaration | PropertyDeclaration ) . initializer || isCatchClause ( decl . parent ) ; case SyntaxKind . MethodSignature : case SyntaxKind . PropertySignature : case SyntaxKind . JSDocPropertyTag : case SyntaxKind . JSDocParameterTag : return false ; default : return Debug . failBadSyntaxKind ( decl ) ; } } /** Encapsulates the core find-all-references algorithm. */ export namespace Core { /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */ export function getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options = { } , sourceFilesSet = new Set ( sourceFiles . map ( f => f . fileName ) ) ) { if ( options . use === FindReferencesUse . References ) { node = getAdjustedReferenceLocation ( node ) ; } else if ( options . use === FindReferencesUse . Rename ) { node = getAdjustedRenameLocation ( node ) ; } if ( isSourceFile ( node ) ) { const resolvedRef = GoToDefinition . getReferenceAtPosition ( node , position , program ) ; if ( ! resolvedRef ?. file ) { return undefined ; } const moduleSymbol = program . getTypeChecker ( ) . getMergedSymbol ( resolvedRef . file . symbol ) ; if ( moduleSymbol ) { return getReferencedSymbolsForModule ( program , moduleSymbol , false , sourceFiles , sourceFilesSet ) ; } const fileIncludeReasons = program . getFileIncludeReasons ( ) ; if ( ! fileIncludeReasons ) { return undefined ; } return [ { definition : { type : DefinitionKind . TripleSlashReference , reference : resolvedRef . reference , file : node } , references : getReferencesForNonModule ( resolvedRef . file , fileIncludeReasons , program ) || emptyArray } ] ; } if ( ! options . implementations ) { const special = getReferencedSymbolsSpecial ( node , sourceFiles , cancellationToken ) ; if ( special ) { return special ; } } const checker = program . getTypeChecker ( ) ; const symbol = checker . getSymbolAtLocation ( isConstructorDeclaration ( node ) && node . parent . name || node ) ; if ( ! symbol ) { if ( ! options . implementations && isStringLiteralLike ( node ) ) { if ( isModuleSpecifierLike ( node ) ) { const fileIncludeReasons = program . getFileIncludeReasons ( ) ; const referencedFileName = node . getSourceFile ( ) . resolvedModules ?. get ( node . text , getModeForUsageLocation ( node . getSourceFile ( ) , node ) ) ?. resolvedFileName ; const referencedFile = referencedFileName ? program . getSourceFile ( referencedFileName ) : undefined ; if ( referencedFile ) { return [ { definition : { type : DefinitionKind . String , node } , references : getReferencesForNonModule ( referencedFile , fileIncludeReasons , program ) || emptyArray } ] ; } } return getReferencesForStringLiteral ( node , sourceFiles , checker , cancellationToken ) ; } return undefined ; } if ( symbol . escapedName === InternalSymbolName . ExportEquals ) { return getReferencedSymbolsForModule ( program , symbol . parent ! , false , sourceFiles , sourceFilesSet ) ; } const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile ( symbol , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ; if ( moduleReferences && ! ( symbol . flags & SymbolFlags . Transient ) ) { return moduleReferences ; } const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration ( node , symbol , checker ) ; const moduleReferencesOfExportTarget = aliasedSymbol && getReferencedSymbolsForModuleIfDeclaredBySourceFile ( aliasedSymbol , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ; const references = getReferencedSymbolsForSymbol ( symbol , node , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) ; return mergeReferences ( program , moduleReferences , references , moduleReferencesOfExportTarget ) ; } export function getReferencesForFileName ( fileName , program , sourceFiles , sourceFilesSet = new Set ( sourceFiles . map ( f => f . fileName ) ) ) { const moduleSymbol = program . getSourceFile ( fileName ) ?. symbol ; if ( moduleSymbol ) { return getReferencedSymbolsForModule ( program , moduleSymbol , false , sourceFiles , sourceFilesSet ) [ 0 ] ?. references || emptyArray ; } const fileIncludeReasons = program . getFileIncludeReasons ( ) ; const referencedFile = program . getSourceFile ( fileName ) ; return referencedFile && fileIncludeReasons && getReferencesForNonModule ( referencedFile , fileIncludeReasons , program ) || emptyArray ; } function getReferencesForNonModule ( referencedFile , refFileMap , program ) { let entries ; const references = refFileMap . get ( referencedFile . path ) || emptyArray ; for ( const ref of references ) { if ( isReferencedFile ( ref ) ) { const referencingFile = program . getSourceFileByPath ( ref . file ) ! ; const location = getReferencedFileLocation ( program . getSourceFileByPath , ref ) ; if ( isReferenceFileLocation ( location ) ) { entries = append ( entries , { kind : EntryKind . Span , fileName : referencingFile . fileName , textSpan : createTextSpanFromRange ( location ) } ) ; } } } return entries ; } function getMergedAliasedSymbolOfNamespaceExportDeclaration ( node , symbol , checker ) { if ( node . parent && isNamespaceExportDeclaration ( node . parent ) ) { const aliasedSymbol = checker . getAliasedSymbol ( symbol ) ; const targetSymbol = checker . getMergedSymbol ( aliasedSymbol ) ; if ( aliasedSymbol !== targetSymbol ) { return targetSymbol ; } } return undefined ; } function getReferencedSymbolsForModuleIfDeclaredBySourceFile ( symbol , program , sourceFiles , cancellationToken , options , sourceFilesSet ) { const moduleSourceFile = ( symbol . flags & SymbolFlags . Module ) && symbol . declarations && find ( symbol . declarations , isSourceFile ) ; if ( ! moduleSourceFile ) return undefined ; const exportEquals = symbol . exports ! . get ( InternalSymbolName . ExportEquals ) ; const moduleReferences = getReferencedSymbolsForModule ( program , symbol , ! ! exportEquals , sourceFiles , sourceFilesSet ) ; if ( ! exportEquals || ! sourceFilesSet . has ( moduleSourceFile . fileName ) ) return moduleReferences ; const checker = program . getTypeChecker ( ) ; symbol = skipAlias ( exportEquals , checker ) ; return mergeReferences ( program , moduleReferences , getReferencedSymbolsForSymbol ( symbol , undefined , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) ) ; } /**
         * Merges the references by sorting them (by file index in sourceFiles and their location in it) that point to same definition symbol
         */ function mergeReferences ( program , ... referencesToMerge ) { let result ; for ( const references of referencesToMerge ) { if ( ! references || ! references . length ) continue ; if ( ! result ) { result = references ; continue ; } for ( const entry of references ) { if ( ! entry . definition || entry . definition . type !== DefinitionKind . Symbol ) { result . push ( entry ) ; continue ; } const symbol = entry . definition . symbol ; const refIndex = findIndex ( result , ref => ! ! ref . definition && ref . definition . type === DefinitionKind . Symbol && ref . definition . symbol === symbol ) ; if ( refIndex === - 1 ) { result . push ( entry ) ; continue ; } const reference = result [ refIndex ] ; result [ refIndex ] = { definition : reference . definition , references : reference . references . concat ( entry . references ) . sort ( ( entry1 , entry2 ) => { const entry1File = getSourceFileIndexOfEntry ( program , entry1 ) ; const entry2File = getSourceFileIndexOfEntry ( program , entry2 ) ; if ( entry1File !== entry2File ) { return compareValues ( entry1File , entry2File ) ; } const entry1Span = getTextSpanOfEntry ( entry1 ) ; const entry2Span = getTextSpanOfEntry ( entry2 ) ; return entry1Span . start !== entry2Span . start ? compareValues ( entry1Span . start , entry2Span . start ) : compareValues ( entry1Span . length , entry2Span . length ) ; } ) } ; } } return result ; } function getSourceFileIndexOfEntry ( program , entry ) { const sourceFile = entry . kind === EntryKind . Span ? program . getSourceFile ( entry . fileName ) ! : entry . node . getSourceFile ( ) ; return program . getSourceFiles ( ) . indexOf ( sourceFile ) ; } function getReferencedSymbolsForModule ( program , symbol , excludeImportTypeOfExportEquals , sourceFiles , sourceFilesSet ) { Debug . assert ( ! ! symbol . valueDeclaration ) ; const references = mapDefined < ModuleReference , Entry > ( findModuleReferences ( program , sourceFiles , symbol ) , reference => { if ( reference . kind === "import" ) { const parent = reference . literal . parent ; if ( isLiteralTypeNode ( parent ) ) { const importType = cast ( parent . parent , isImportTypeNode ) ; if ( excludeImportTypeOfExportEquals && ! importType . qualifier ) { return undefined ; } } return nodeEntry ( reference . literal ) ; } else { return { kind : EntryKind . Span , fileName : reference . referencingFile . fileName , textSpan : createTextSpanFromRange ( reference . ref ) , } ; } } ) ; if ( symbol . declarations ) { for ( const decl of symbol . declarations ) { switch ( decl . kind ) { case SyntaxKind . SourceFile : break ; case SyntaxKind . ModuleDeclaration : if ( sourceFilesSet . has ( decl . getSourceFile ( ) . fileName ) ) { references . push ( nodeEntry ( ( decl as ModuleDeclaration ) . name ) ) ; } break ; default : Debug . assert ( ! ! ( symbol . flags & SymbolFlags . Transient ) , "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration." ) ; } } } const exported = symbol . exports ! . get ( InternalSymbolName . ExportEquals ) ; if ( exported ?. declarations ) { for ( const decl of exported . declarations ) { const sourceFile = decl . getSourceFile ( ) ; if ( sourceFilesSet . has ( sourceFile . fileName ) ) { const node = isBinaryExpression ( decl ) && isPropertyAccessExpression ( decl . left ) ? decl . left . expression : isExportAssignment ( decl ) ? Debug . checkDefined ( findChildOfKind ( decl , SyntaxKind . ExportKeyword , sourceFile ) ) : getNameOfDeclaration ( decl ) || decl ; references . push ( nodeEntry ( node ) ) ; } } } return references . length ? [ { definition : { type : DefinitionKind . Symbol , symbol } , references } ] : emptyArray ; } /** As in a `readonly prop: any` or `constructor(readonly prop: any)`, not a `readonly any[]`. */ function isReadonlyTypeOperator ( node ) { return node . kind === SyntaxKind . ReadonlyKeyword && isTypeOperatorNode ( node . parent ) && node . parent . operator === SyntaxKind . ReadonlyKeyword ; } /** getReferencedSymbols for special node kinds. */ function getReferencedSymbolsSpecial ( node , sourceFiles , cancellationToken ) { if ( isTypeKeyword ( node . kind ) ) { if ( node . kind === SyntaxKind . VoidKeyword && isVoidExpression ( node . parent ) ) { return undefined ; } if ( node . kind === SyntaxKind . ReadonlyKeyword && ! isReadonlyTypeOperator ( node ) ) { return undefined ; } return getAllReferencesForKeyword ( sourceFiles , node . kind , cancellationToken , node . kind === SyntaxKind . ReadonlyKeyword ? isReadonlyTypeOperator : undefined ) ; } if ( isStaticModifier ( node ) && isClassStaticBlockDeclaration ( node . parent ) ) { return [ { definition : { type : DefinitionKind . Keyword , node } , references : [ nodeEntry ( node ) ] } ] ; } if ( isJumpStatementTarget ( node ) ) { const labelDefinition = getTargetLabel ( node . parent , node . text ) ; return labelDefinition && getLabelReferencesInNode ( labelDefinition . parent , labelDefinition ) ; } else if ( isLabelOfLabeledStatement ( node ) ) { return getLabelReferencesInNode ( node . parent , node ) ; } if ( isThis ( node ) ) { return getReferencesForThisKeyword ( node , sourceFiles , cancellationToken ) ; } if ( node . kind === SyntaxKind . SuperKeyword ) { return getReferencesForSuperKeyword ( node ) ; } return undefined ; } /** Core find-all-references algorithm for a normal symbol. */ function getReferencedSymbolsForSymbol ( originalSymbol , node , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) { const symbol = node && skipPastExportOrImportSpecifierOrUnion ( originalSymbol , node , checker , ! isForRenameWithPrefixAndSuffixText ( options ) ) || originalSymbol ; const searchMeaning = node ? getIntersectingMeaningFromDeclarations ( node , symbol ) : SemanticMeaning . All ; const result = [ ] ; const state = new State ( sourceFiles , sourceFilesSet , node ? getSpecialSearchKind ( node ) : SpecialSearchKind . None , checker , cancellationToken , searchMeaning , options , result ) ; const exportSpecifier = ! isForRenameWithPrefixAndSuffixText ( options ) || ! symbol . declarations ? undefined : find ( symbol . declarations , isExportSpecifier ) ; if ( exportSpecifier ) { getReferencesAtExportSpecifier ( exportSpecifier . name , symbol , exportSpecifier , state . createSearch ( node , originalSymbol , undefined ) , state , true , true ) ; } else if ( node && node . kind === SyntaxKind . DefaultKeyword && symbol . escapedName === InternalSymbolName . Default && symbol . parent ) { addReference ( node , symbol , state ) ; searchForImportsOfExport ( node , symbol , { exportingModuleSymbol : symbol . parent , exportKind : ExportKind . Default } , state ) ; } else { const search = state . createSearch ( node , symbol , undefined , { allSearchSymbols : node ? populateSearchSymbolSet ( symbol , node , checker , options . use === FindReferencesUse . Rename , ! ! options . providePrefixAndSuffixTextForRename , ! ! options . implementations ) : [ symbol ] } ) ; getReferencesInContainerOrFiles ( symbol , state , search ) ; } return result ; } function getReferencesInContainerOrFiles ( symbol , state , search ) { const scope = getSymbolScope ( symbol ) ; if ( scope ) { getReferencesInContainer ( scope , scope . getSourceFile ( ) , search , state , ! ( isSourceFile ( scope ) && ! contains ( state . sourceFiles , scope ) ) ) ; } else { for ( const sourceFile of state . sourceFiles ) { state . cancellationToken . throwIfCancellationRequested ( ) ; searchForName ( sourceFile , search , state ) ; } } } function getSpecialSearchKind ( node ) { switch ( node . kind ) { case SyntaxKind . Constructor : case SyntaxKind . ConstructorKeyword : return SpecialSearchKind . Constructor ; case SyntaxKind . Identifier : if ( isClassLike ( node . parent ) ) { Debug . assert ( node . parent . name === node ) ; return SpecialSearchKind . Class ; } default : return SpecialSearchKind . None ; } } /** Handle a few special cases relating to export/import specifiers. */ function skipPastExportOrImportSpecifierOrUnion ( symbol , node , checker , useLocalSymbolForExportSpecifier ) { const { parent } = node ; if ( isExportSpecifier ( parent ) && useLocalSymbolForExportSpecifier ) { return getLocalSymbolForExportSpecifier ( node as Identifier , symbol , parent , checker ) ; } return firstDefined ( symbol . declarations , decl => { if ( ! decl . parent ) { if ( symbol . flags & SymbolFlags . Transient ) return undefined ; Debug . fail ( `Unexpected symbol at ${ Debug . formatSyntaxKind ( node . kind ) }: ${ Debug . formatSymbol ( symbol ) }` ) ; } return isTypeLiteralNode ( decl . parent ) && isUnionTypeNode ( decl . parent . parent ) ? checker . getPropertyOfType ( checker . getTypeFromTypeNode ( decl . parent . parent ) , symbol . name ) : undefined ; } ) ; } /**
         * Symbol that is currently being searched for.
         * This will be replaced if we find an alias for the symbol.
         */ interface Search { /** If coming from an export, we will not recursively search for the imported symbol (since that's where we came from). */ readonly comingFrom ? : ImportExport ; readonly symbol : Symbol ; readonly text : string ; readonly escapedText : __String ; /** Only set if `options.implementations` is true. These are the symbols checked to get the implementations of a property access. */ readonly parents : readonly Symbol [ ] | undefined ; readonly allSearchSymbols : readonly Symbol [ ] ; /**
             * Whether a symbol is in the search set.
             * Do not compare directly to `symbol` because there may be related symbols to search for. See `populateSearchSymbolSet`.
             */ includes ( symbol ) : boolean ; } const enum SpecialSearchKind { None , Constructor , Class } function getNonModuleSymbolOfMergedModuleSymbol ( symbol ) { if ( ! ( symbol . flags & ( SymbolFlags . Module | SymbolFlags . Transient ) ) ) return undefined ; const decl = symbol . declarations && find ( symbol . declarations , d => ! isSourceFile ( d ) && ! isModuleDeclaration ( d ) ) ; return decl && decl . symbol ; } /**
         * Holds all state needed for the finding references.
         * Unlike `Search`, there is only one `State`.
         */ class State { /** Cache for `explicitlyinheritsFrom`. */ readonly inheritsFromCache = new Map < string , boolean > ( ) ; /**
             * Type nodes can contain multiple references to the same type. For example:
             *      let x: Foo & (Foo & Bar) = ...
             * Because we are returning the implementation locations and not the identifier locations,
             * duplicate entries would be returned here as each of the type references is part of
             * the same implementation. For that reason, check before we add a new entry.
             */ readonly markSeenContainingTypeReference = nodeSeenTracker ( ) ; /**
             * It's possible that we will encounter the right side of `export { foo as bar } from "x";` more than once.
             * For example:
             *     // b.ts
             *     export { foo as bar } from "./a";
             *     import { bar } from "./b";
             *
             * Normally at `foo as bar` we directly add `foo` and do not locally search for it (since it doesn't declare a local).
             * But another reference to it may appear in the same source file.
             * See `tests/cases/fourslash/transitiveExportImports3.ts`.
             */ readonly markSeenReExportRHS = nodeSeenTracker ( ) ; constructor ( readonly sourceFiles , readonly sourceFilesSet , readonly specialSearchKind , readonly checker , readonly cancellationToken , readonly searchMeaning , readonly options , private readonly result ) { } includesSourceFile ( sourceFile ) { return this . sourceFilesSet . has ( sourceFile . fileName ) ; } private importTracker : ImportTracker | undefined ; /** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */ getImportSearches ( exportSymbol , exportInfo ) { if ( ! this . importTracker ) this . importTracker = createImportTracker ( this . sourceFiles , this . sourceFilesSet , this . checker , this . cancellationToken ) ; return this . importTracker ( exportSymbol , exportInfo , this . options . use === FindReferencesUse . Rename ) ; } param allSearchSymbols createSearch ( location , symbol , comingFrom , searchOptions = { } ) { const { text = stripQuotes ( symbolName ( getLocalSymbolForExportDefault ( symbol ) || getNonModuleSymbolOfMergedModuleSymbol ( symbol ) || symbol ) ) , allSearchSymbols = [ symbol ] , } = searchOptions ; const escapedText = escapeLeadingUnderscores ( text ) ; const parents = this . options . implementations && location ? getParentSymbolsOfPropertyAccess ( location , symbol , this . checker ) : undefined ; return { symbol , comingFrom , text , escapedText , parents , allSearchSymbols , includes : sym => contains ( allSearchSymbols , sym ) } ; } private readonly symbolIdToReferences : Entry [ ] [ ] = [ ] ; /**
             * Callback to add references for a particular searched symbol.
             * This initializes a reference group, so only call this if you will add at least one reference.
             */ referenceAdder ( searchSymbol ) { const symbolId = getSymbolId ( searchSymbol ) ; let references = this . symbolIdToReferences [ symbolId ] ; if ( ! references ) { references = this . symbolIdToReferences [ symbolId ] = [ ] ; this . result . push ( { definition : { type : DefinitionKind . Symbol , symbol : searchSymbol } , references } ) ; } return ( node , kind ) => references . push ( nodeEntry ( node , kind ) ) ; } /** Add a reference with no associated definition. */ addStringOrCommentReference ( fileName , textSpan ) { this . result . push ( { definition : undefined , references : [ { kind : EntryKind . Span , fileName , textSpan } ] } ) ; } private readonly sourceFileToSeenSymbols : Set < number > [ ] = [ ] ; /** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */ markSearchedSymbols ( sourceFile , symbols ) { const sourceId = getNodeId ( sourceFile ) ; const seenSymbols = this . sourceFileToSeenSymbols [ sourceId ] || ( this . sourceFileToSeenSymbols [ sourceId ] = new Set < number > ( ) ) ; let anyNewSymbols = false ; for ( const sym of symbols ) { anyNewSymbols = tryAddToSet ( seenSymbols , getSymbolId ( sym ) ) || anyNewSymbols ; } return anyNewSymbols ; } } /** Search for all imports of a given exported symbol using `State.getImportSearches`. */ function searchForImportsOfExport ( exportLocation , exportSymbol , exportInfo , state ) { const { importSearches , singleReferences , indirectUsers } = state . getImportSearches ( exportSymbol , exportInfo ) ; if ( singleReferences . length ) { const addRef = state . referenceAdder ( exportSymbol ) ; for ( const singleRef of singleReferences ) { if ( shouldAddSingleReference ( singleRef , state ) ) addRef ( singleRef ) ; } } for ( const [ importLocation , importSymbol ] of importSearches ) { getReferencesInSourceFile ( importLocation . getSourceFile ( ) , state . createSearch ( importLocation , importSymbol , ImportExport . Export ) , state ) ; } if ( indirectUsers . length ) { let indirectSearch ; switch ( exportInfo . exportKind ) { case ExportKind . Named : indirectSearch = state . createSearch ( exportLocation , exportSymbol , ImportExport . Export ) ; break ; case ExportKind . Default : indirectSearch = state . options . use === FindReferencesUse . Rename ? undefined : state . createSearch ( exportLocation , exportSymbol , ImportExport . Export , { text : "default" } ) ; break ; case ExportKind . ExportEquals : break ; } if ( indirectSearch ) { for ( const indirectUser of indirectUsers ) { searchForName ( indirectUser , indirectSearch , state ) ; } } } } export function eachExportReference ( sourceFiles , checker , cancellationToken , exportSymbol , exportingModuleSymbol , exportName , isDefaultExport , cb ) { const importTracker = createImportTracker ( sourceFiles , new Set ( sourceFiles . map ( f => f . fileName ) ) , checker , cancellationToken ) ; const { importSearches , indirectUsers } = importTracker ( exportSymbol , { exportKind : isDefaultExport ? ExportKind . Default : ExportKind . Named , exportingModuleSymbol } , false ) ; for ( const [ importLocation ] of importSearches ) { cb ( importLocation ) ; } for ( const indirectUser of indirectUsers ) { for ( const node of getPossibleSymbolReferenceNodes ( indirectUser , isDefaultExport ? "default" : exportName ) ) { const symbol = checker . getSymbolAtLocation ( node ) ; const hasExportAssignmentDeclaration = some ( symbol ?. declarations , d => tryCast ( d , isExportAssignment ) ? true : false ) ; if ( isIdentifier ( node ) && ! isImportOrExportSpecifier ( node . parent ) && ( symbol === exportSymbol || hasExportAssignmentDeclaration ) ) { cb ( node ) ; } } } } function shouldAddSingleReference ( singleRef , state ) { if ( ! hasMatchingMeaning ( singleRef , state ) ) return false ; if ( state . options . use !== FindReferencesUse . Rename ) return true ; if ( ! isIdentifier ( singleRef ) ) return false ; return ! ( isImportOrExportSpecifier ( singleRef . parent ) && singleRef . escapedText === InternalSymbolName . Default ) ; } function searchForImportedSymbol ( symbol , state ) { if ( ! symbol . declarations ) return ; for ( const declaration of symbol . declarations ) { const exportingFile = declaration . getSourceFile ( ) ; getReferencesInSourceFile ( exportingFile , state . createSearch ( declaration , symbol , ImportExport . Import ) , state , state . includesSourceFile ( exportingFile ) ) ; } } /** Search for all occurrences of an identifier in a source file (and filter out the ones that match). */ function searchForName ( sourceFile , search , state ) { if ( getNameTable ( sourceFile ) . get ( search . escapedText ) !== undefined ) { getReferencesInSourceFile ( sourceFile , search , state ) ; } } function getPropertySymbolOfDestructuringAssignment ( location , checker ) { return isArrayLiteralOrObjectLiteralDestructuringPattern ( location . parent . parent ) ? checker . getPropertySymbolOfDestructuringAssignment ( location as Identifier ) : undefined ; } returns function getSymbolScope ( symbol ) { const { declarations , flags , parent , valueDeclaration } = symbol ; if ( valueDeclaration && ( valueDeclaration . kind === SyntaxKind . FunctionExpression || valueDeclaration . kind === SyntaxKind . ClassExpression ) ) { return valueDeclaration ; } if ( ! declarations ) { return undefined ; } if ( flags & ( SymbolFlags . Property | SymbolFlags . Method ) ) { const privateDeclaration = find ( declarations , d => hasEffectiveModifier ( d , ModifierFlags . Private ) || isPrivateIdentifierClassElementDeclaration ( d ) ) ; if ( privateDeclaration ) { return getAncestor ( privateDeclaration , SyntaxKind . ClassDeclaration ) ; } return undefined ; } if ( declarations . some ( isObjectBindingElementWithoutPropertyName ) ) { return undefined ; } const exposedByParent = parent && ! ( symbol . flags & SymbolFlags . TypeParameter ) ; if ( exposedByParent && ! ( isExternalModuleSymbol ( parent ! ) && ! parent ! . globalExports ) ) { return undefined ; } let scope ; for ( const declaration of declarations ) { const container = getContainerNode ( declaration ) ; if ( scope && scope !== container ) { return undefined ; } if ( ! container || container . kind === SyntaxKind . SourceFile && ! isExternalOrCommonJsModule ( container as SourceFile ) ) { return undefined ; } scope = container ; if ( isFunctionExpression ( scope ) ) { let next ; while ( next = getNextJSDocCommentLocation ( scope ) ) { scope = next ; } } } return exposedByParent ? scope ! . getSourceFile ( ) : scope ; } /** Used as a quick check for whether a symbol is used at all in a file (besides its definition). */ export function isSymbolReferencedInFile ( definition , checker , sourceFile , searchContainer = sourceFile ) { return eachSymbolReferenceInFile ( definition , checker , sourceFile , ( ) => true , searchContainer ) || false ; } export function eachSymbolReferenceInFile < T > ( definition , checker , sourceFile , cb , searchContainer = sourceFile ) { const symbol = isParameterPropertyDeclaration ( definition . parent , definition . parent . parent ) ? first ( checker . getSymbolsOfParameterPropertyDeclaration ( definition . parent , definition . text ) ) : checker . getSymbolAtLocation ( definition ) ; if ( ! symbol ) return undefined ; for ( const token of getPossibleSymbolReferenceNodes ( sourceFile , symbol . name , searchContainer ) ) { if ( ! isIdentifier ( token ) || token === definition || token . escapedText !== definition . escapedText ) continue ; const referenceSymbol = checker . getSymbolAtLocation ( token ) ! ; if ( referenceSymbol === symbol || checker . getShorthandAssignmentValueSymbol ( token . parent ) === symbol || isExportSpecifier ( token . parent ) && getLocalSymbolForExportSpecifier ( token , referenceSymbol , token . parent , checker ) === symbol ) { const res = cb ( token ) ; if ( res ) return res ; } } } export function someSignatureUsage ( signature , sourceFiles , checker , cb ) { if ( ! signature . name || ! isIdentifier ( signature . name ) ) return false ; const symbol = Debug . checkDefined ( checker . getSymbolAtLocation ( signature . name ) ) ; for ( const sourceFile of sourceFiles ) { for ( const name of getPossibleSymbolReferenceNodes ( sourceFile , symbol . name ) ) { if ( ! isIdentifier ( name ) || name === signature . name || name . escapedText !== signature . name . escapedText ) continue ; const called = climbPastPropertyAccess ( name ) ; const call = isCallExpression ( called . parent ) && called . parent . expression === called ? called . parent : undefined ; const referenceSymbol = checker . getSymbolAtLocation ( name ) ; if ( referenceSymbol && checker . getRootSymbols ( referenceSymbol ) . some ( s => s === symbol ) ) { if ( cb ( name , call ) ) { return true ; } } } } return false ; } function getPossibleSymbolReferenceNodes ( sourceFile , symbolName , container = sourceFile ) { return getPossibleSymbolReferencePositions ( sourceFile , symbolName , container ) . map ( pos => getTouchingPropertyName ( sourceFile , pos ) ) ; } function getPossibleSymbolReferencePositions ( sourceFile , symbolName , container = sourceFile ) { const positions = [ ] ; if ( ! symbolName || ! symbolName . length ) { return positions ; } const text = sourceFile . text ; const sourceLength = text . length ; const symbolNameLength = symbolName . length ; let position = text . indexOf ( symbolName , container . pos ) ; while ( position >= 0 ) { if ( position > container . end ) break ; const endPosition = position + symbolNameLength ; if ( ( position === 0 || ! isIdentifierPart ( text . charCodeAt ( position - 1 ) , ScriptTarget . Latest ) ) && ( endPosition === sourceLength || ! isIdentifierPart ( text . charCodeAt ( endPosition ) , ScriptTarget . Latest ) ) ) { positions . push ( position ) ; } position = text . indexOf ( symbolName , position + symbolNameLength + 1 ) ; } return positions ; } function getLabelReferencesInNode ( container , targetLabel ) { const sourceFile = container . getSourceFile ( ) ; const labelName = targetLabel . text ; const references = mapDefined ( getPossibleSymbolReferenceNodes ( sourceFile , labelName , container ) , node => node === targetLabel || ( isJumpStatementTarget ( node ) && getTargetLabel ( node , labelName ) === targetLabel ) ? nodeEntry ( node ) : undefined ) ; return [ { definition : { type : DefinitionKind . Label , node : targetLabel } , references } ] ; } function isValidReferencePosition ( node , searchSymbolName ) { switch ( node . kind ) { case SyntaxKind . PrivateIdentifier : if ( isJSDocMemberName ( node . parent ) ) { return true ; } case SyntaxKind . Identifier : return ( node as PrivateIdentifier | Identifier ) . text . length === searchSymbolName . length ; case SyntaxKind . NoSubstitutionTemplateLiteral : case SyntaxKind . StringLiteral : { const str = node as StringLiteralLike ; return ( isLiteralNameOfPropertyDeclarationOrIndexAccess ( str ) || isNameOfModuleDeclaration ( node ) || isExpressionOfExternalModuleImportEqualsDeclaration ( node ) || ( isCallExpression ( node . parent ) && isBindableObjectDefinePropertyCall ( node . parent ) && node . parent . arguments [ 1 ] === node ) ) && str . text . length === searchSymbolName . length ; } case SyntaxKind . NumericLiteral : return isLiteralNameOfPropertyDeclarationOrIndexAccess ( node as NumericLiteral ) && ( node as NumericLiteral ) . text . length === searchSymbolName . length ; case SyntaxKind . DefaultKeyword : return "default" . length === searchSymbolName . length ; default : return false ; } } function getAllReferencesForKeyword ( sourceFiles , keywordKind , cancellationToken , filter ? ) { const references = flatMap ( sourceFiles , sourceFile => { cancellationToken . throwIfCancellationRequested ( ) ; return mapDefined ( getPossibleSymbolReferenceNodes ( sourceFile , tokenToString ( keywordKind ) ! , sourceFile ) , referenceLocation => { if ( referenceLocation . kind === keywordKind && ( ! filter || filter ( referenceLocation ) ) ) { return nodeEntry ( referenceLocation ) ; } } ) ; } ) ; return references . length ? [ { definition : { type : DefinitionKind . Keyword , node : references [ 0 ] . node } , references } ] : undefined ; } function getReferencesInSourceFile ( sourceFile , search , state , addReferencesHere = true ) { state . cancellationToken . throwIfCancellationRequested ( ) ; return getReferencesInContainer ( sourceFile , sourceFile , search , state , addReferencesHere ) ; } /**
         * Search within node "container" for references for a search value, where the search value is defined as a
         * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
         * searchLocation: a node where the search value
         */ function getReferencesInContainer ( container , sourceFile , search , state , addReferencesHere ) { if ( ! state . markSearchedSymbols ( sourceFile , search . allSearchSymbols ) ) { return ; } for ( const position of getPossibleSymbolReferencePositions ( sourceFile , search . text , container ) ) { getReferencesAtLocation ( sourceFile , position , search , state , addReferencesHere ) ; } } function hasMatchingMeaning ( referenceLocation , state ) { return ! ! ( getMeaningFromLocation ( referenceLocation ) & state . searchMeaning ) ; } function getReferencesAtLocation ( sourceFile , position , search , state , addReferencesHere ) { const referenceLocation = getTouchingPropertyName ( sourceFile , position ) ; if ( ! isValidReferencePosition ( referenceLocation , search . text ) ) { if ( ! state . options . implementations && ( state . options . findInStrings && isInString ( sourceFile , position ) || state . options . findInComments && isInNonReferenceComment ( sourceFile , position ) ) ) { state . addStringOrCommentReference ( sourceFile . fileName , createTextSpan ( position , search . text . length ) ) ; } return ; } if ( ! hasMatchingMeaning ( referenceLocation , state ) ) return ; let referenceSymbol = state . checker . getSymbolAtLocation ( referenceLocation ) ; if ( ! referenceSymbol ) { return ; } const parent = referenceLocation . parent ; if ( isImportSpecifier ( parent ) && parent . propertyName === referenceLocation ) { return ; } if ( isExportSpecifier ( parent ) ) { Debug . assert ( referenceLocation . kind === SyntaxKind . Identifier ) ; getReferencesAtExportSpecifier ( referenceLocation as Identifier , referenceSymbol , parent , search , state , addReferencesHere ) ; return ; } const relatedSymbol = getRelatedSymbol ( search , referenceSymbol , referenceLocation , state ) ; if ( ! relatedSymbol ) { getReferenceForShorthandProperty ( referenceSymbol , search , state ) ; return ; } switch ( state . specialSearchKind ) { case SpecialSearchKind . None : if ( addReferencesHere ) addReference ( referenceLocation , relatedSymbol , state ) ; break ; case SpecialSearchKind . Constructor : addConstructorReferences ( referenceLocation , sourceFile , search , state ) ; break ; case SpecialSearchKind . Class : addClassStaticThisReferences ( referenceLocation , search , state ) ; break ; default : Debug . assertNever ( state . specialSearchKind ) ; } if ( isInJSFile ( referenceLocation ) && referenceLocation . parent . kind === SyntaxKind . BindingElement && isRequireVariableDeclaration ( referenceLocation . parent ) ) { referenceSymbol = referenceLocation . parent . symbol ; if ( ! referenceSymbol ) return ; } getImportOrExportReferences ( referenceLocation , referenceSymbol , search , state ) ; } function getReferencesAtExportSpecifier ( referenceLocation , referenceSymbol , exportSpecifier , search , state , addReferencesHere , alwaysGetReferences ? ) { Debug . assert ( ! alwaysGetReferences || ! ! state . options . providePrefixAndSuffixTextForRename , "If alwaysGetReferences is true, then prefix/suffix text must be enabled" ) ; const { parent , propertyName , name } = exportSpecifier ; const exportDeclaration = parent . parent ; const localSymbol = getLocalSymbolForExportSpecifier ( referenceLocation , referenceSymbol , exportSpecifier , state . checker ) ; if ( ! alwaysGetReferences && ! search . includes ( localSymbol ) ) { return ; } if ( ! propertyName ) { if ( ! ( state . options . use === FindReferencesUse . Rename && ( name . escapedText === InternalSymbolName . Default ) ) ) { addRef ( ) ; } } else if ( referenceLocation === propertyName ) { if ( ! exportDeclaration . moduleSpecifier ) { addRef ( ) ; } if ( addReferencesHere && state . options . use !== FindReferencesUse . Rename && state . markSeenReExportRHS ( name ) ) { addReference ( name , Debug . checkDefined ( exportSpecifier . symbol ) , state ) ; } } else { if ( state . markSeenReExportRHS ( referenceLocation ) ) { addRef ( ) ; } } if ( ! isForRenameWithPrefixAndSuffixText ( state . options ) || alwaysGetReferences ) { const isDefaultExport = referenceLocation . originalKeywordKind === SyntaxKind . DefaultKeyword || exportSpecifier . name . originalKeywordKind === SyntaxKind . DefaultKeyword ; const exportKind = isDefaultExport ? ExportKind . Default : ExportKind . Named ; const exportSymbol = Debug . checkDefined ( exportSpecifier . symbol ) ; const exportInfo = getExportInfo ( exportSymbol , exportKind , state . checker ) ; if ( exportInfo ) { searchForImportsOfExport ( referenceLocation , exportSymbol , exportInfo , state ) ; } } if ( search . comingFrom !== ImportExport . Export && exportDeclaration . moduleSpecifier && ! propertyName && ! isForRenameWithPrefixAndSuffixText ( state . options ) ) { const imported = state . checker . getExportSpecifierLocalTargetSymbol ( exportSpecifier ) ; if ( imported ) searchForImportedSymbol ( imported , state ) ; } function addRef ( ) { if ( addReferencesHere ) addReference ( referenceLocation , localSymbol , state ) ; } } function getLocalSymbolForExportSpecifier ( referenceLocation , referenceSymbol , exportSpecifier , checker ) { return isExportSpecifierAlias ( referenceLocation , exportSpecifier ) && checker . getExportSpecifierLocalTargetSymbol ( exportSpecifier ) || referenceSymbol ; } function isExportSpecifierAlias ( referenceLocation , exportSpecifier ) { const { parent , propertyName , name } = exportSpecifier ; Debug . assert ( propertyName === referenceLocation || name === referenceLocation ) ; if ( propertyName ) { return propertyName === referenceLocation ; } else { return ! parent . parent . moduleSpecifier ; } } function getImportOrExportReferences ( referenceLocation , referenceSymbol , search , state ) { const importOrExport = getImportOrExportSymbol ( referenceLocation , referenceSymbol , state . checker , search . comingFrom === ImportExport . Export ) ; if ( ! importOrExport ) return ; const { symbol } = importOrExport ; if ( importOrExport . kind === ImportExport . Import ) { if ( ! ( isForRenameWithPrefixAndSuffixText ( state . options ) ) ) { searchForImportedSymbol ( symbol , state ) ; } } else { searchForImportsOfExport ( referenceLocation , symbol , importOrExport . exportInfo , state ) ; } } function getReferenceForShorthandProperty ( { flags , valueDeclaration } , search , state ) { const shorthandValueSymbol = state . checker . getShorthandAssignmentValueSymbol ( valueDeclaration ) ! ; const name = valueDeclaration && getNameOfDeclaration ( valueDeclaration ) ; if ( ! ( flags & SymbolFlags . Transient ) && name && search . includes ( shorthandValueSymbol ) ) { addReference ( name , shorthandValueSymbol , state ) ; } } function addReference ( referenceLocation , relatedSymbol , state ) { const { kind , symbol } = "kind" in relatedSymbol ? relatedSymbol : { kind : undefined , symbol : relatedSymbol } ; const addRef = state . referenceAdder ( symbol ) ; if ( state . options . implementations ) { addImplementationReferences ( referenceLocation , addRef , state ) ; } else { addRef ( referenceLocation , kind ) ; } } /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses.  */ function addConstructorReferences ( referenceLocation , sourceFile , search , state ) { if ( isNewExpressionTarget ( referenceLocation ) ) { addReference ( referenceLocation , search . symbol , state ) ; } const pusher = ( ) => state . referenceAdder ( search . symbol ) ; if ( isClassLike ( referenceLocation . parent ) ) { Debug . assert ( referenceLocation . kind === SyntaxKind . DefaultKeyword || referenceLocation . parent . name === referenceLocation ) ; findOwnConstructorReferences ( search . symbol , sourceFile , pusher ( ) ) ; } else { const classExtending = tryGetClassByExtendingIdentifier ( referenceLocation ) ; if ( classExtending ) { findSuperConstructorAccesses ( classExtending , pusher ( ) ) ; findInheritedConstructorReferences ( classExtending , state ) ; } } } function addClassStaticThisReferences ( referenceLocation , search , state ) { addReference ( referenceLocation , search . symbol , state ) ; const classLike = referenceLocation . parent ; if ( state . options . use === FindReferencesUse . Rename || ! isClassLike ( classLike ) ) return ; Debug . assert ( classLike . name === referenceLocation ) ; const addRef = state . referenceAdder ( search . symbol ) ; for ( const member of classLike . members ) { if ( ! ( isMethodOrAccessor ( member ) && isStatic ( member ) ) ) { continue ; } if ( member . body ) { member . body . forEachChild ( function cb ( node ) { if ( node . kind === SyntaxKind . ThisKeyword ) { addRef ( node ) ; } else if ( ! isFunctionLike ( node ) && ! isClassLike ( node ) ) { node . forEachChild ( cb ) ; } } ) ; } } } /**
         * `classSymbol` is the class where the constructor was defined.
         * Reference the constructor and all calls to `new this()`.
         */ function findOwnConstructorReferences ( classSymbol , sourceFile , addNode ) { const constructorSymbol = getClassConstructorSymbol ( classSymbol ) ; if ( constructorSymbol && constructorSymbol . declarations ) { for ( const decl of constructorSymbol . declarations ) { const ctrKeyword = findChildOfKind ( decl , SyntaxKind . ConstructorKeyword , sourceFile ) ! ; Debug . assert ( decl . kind === SyntaxKind . Constructor && ! ! ctrKeyword ) ; addNode ( ctrKeyword ) ; } } if ( classSymbol . exports ) { classSymbol . exports . forEach ( member => { const decl = member . valueDeclaration ; if ( decl && decl . kind === SyntaxKind . MethodDeclaration ) { const body = ( decl as MethodDeclaration ) . body ; if ( body ) { forEachDescendantOfKind ( body , SyntaxKind . ThisKeyword , thisKeyword => { if ( isNewExpressionTarget ( thisKeyword ) ) { addNode ( thisKeyword ) ; } } ) ; } } } ) ; } } function getClassConstructorSymbol ( classSymbol ) { return classSymbol . members && classSymbol . members . get ( InternalSymbolName . Constructor ) ; } /** Find references to `super` in the constructor of an extending class.  */ function findSuperConstructorAccesses ( classDeclaration , addNode ) { const constructor = getClassConstructorSymbol ( classDeclaration . symbol ) ; if ( ! ( constructor && constructor . declarations ) ) { return ; } for ( const decl of constructor . declarations ) { Debug . assert ( decl . kind === SyntaxKind . Constructor ) ; const body = ( decl as ConstructorDeclaration ) . body ; if ( body ) { forEachDescendantOfKind ( body , SyntaxKind . SuperKeyword , node => { if ( isCallExpressionTarget ( node ) ) { addNode ( node ) ; } } ) ; } } } function hasOwnConstructor ( classDeclaration ) { return ! ! getClassConstructorSymbol ( classDeclaration . symbol ) ; } function findInheritedConstructorReferences ( classDeclaration , state ) { if ( hasOwnConstructor ( classDeclaration ) ) return ; const classSymbol = classDeclaration . symbol ; const search = state . createSearch ( undefined , classSymbol , undefined ) ; getReferencesInContainerOrFiles ( classSymbol , state , search ) ; } function addImplementationReferences ( refNode , addReference , state ) { if ( isDeclarationName ( refNode ) && isImplementation ( refNode . parent ) ) { addReference ( refNode ) ; return ; } if ( refNode . kind !== SyntaxKind . Identifier ) { return ; } if ( refNode . parent . kind === SyntaxKind . ShorthandPropertyAssignment ) { getReferenceEntriesForShorthandPropertyAssignment ( refNode , state . checker , addReference ) ; } const containingClass = getContainingClassIfInHeritageClause ( refNode ) ; if ( containingClass ) { addReference ( containingClass ) ; return ; } const typeNode = findAncestor ( refNode , a => ! isQualifiedName ( a . parent ) && ! isTypeNode ( a . parent ) && ! isTypeElement ( a . parent ) ) ! ; const typeHavingNode = typeNode . parent ; if ( hasType ( typeHavingNode ) && typeHavingNode . type === typeNode && state . markSeenContainingTypeReference ( typeHavingNode ) ) { if ( hasInitializer ( typeHavingNode ) ) { addIfImplementation ( typeHavingNode . initializer ! ) ; } else if ( isFunctionLike ( typeHavingNode ) && ( typeHavingNode as FunctionLikeDeclaration ) . body ) { const body = ( typeHavingNode as FunctionLikeDeclaration ) . body ! ; if ( body . kind === SyntaxKind . Block ) { forEachReturnStatement ( body as Block , returnStatement => { if ( returnStatement . expression ) addIfImplementation ( returnStatement . expression ) ; } ) ; } else { addIfImplementation ( body ) ; } } else if ( isAssertionExpression ( typeHavingNode ) ) { addIfImplementation ( typeHavingNode . expression ) ; } } function addIfImplementation ( e ) { if ( isImplementationExpression ( e ) ) addReference ( e ) ; } } function getContainingClassIfInHeritageClause ( node ) { return isIdentifier ( node ) || isPropertyAccessExpression ( node ) ? getContainingClassIfInHeritageClause ( node . parent ) : isExpressionWithTypeArguments ( node ) ? tryCast ( node . parent . parent , isClassLike ) : undefined ; } /**
         * Returns true if this is an expression that can be considered an implementation
         */ function isImplementationExpression ( node ) { switch ( node . kind ) { case SyntaxKind . ParenthesizedExpression : return isImplementationExpression ( ( node as ParenthesizedExpression ) . expression ) ; case SyntaxKind . ArrowFunction : case SyntaxKind . FunctionExpression : case SyntaxKind . ObjectLiteralExpression : case SyntaxKind . ClassExpression : case SyntaxKind . ArrayLiteralExpression : return true ; default : return false ; } } param symbol param parent param cachedResults function explicitlyInheritsFrom ( symbol , parent , cachedResults , checker ) { if ( symbol === parent ) { return true ; } const key = getSymbolId ( symbol ) + "," + getSymbolId ( parent ) ; const cached = cachedResults . get ( key ) ; if ( cached !== undefined ) { return cached ; } cachedResults . set ( key , false ) ; const inherits = ! ! symbol . declarations && symbol . declarations . some ( declaration => getAllSuperTypeNodes ( declaration ) . some ( typeReference => { const type = checker . getTypeAtLocation ( typeReference ) ; return ! ! type && ! ! type . symbol && explicitlyInheritsFrom ( type . symbol , parent , cachedResults , checker ) ; } ) ) ; cachedResults . set ( key , inherits ) ; return inherits ; } function getReferencesForSuperKeyword ( superKeyword ) { let searchSpaceNode = getSuperContainer ( superKeyword , false ) ; if ( ! searchSpaceNode ) { return undefined ; } let staticFlag = ModifierFlags . Static ; switch ( searchSpaceNode . kind ) { case SyntaxKind . PropertyDeclaration : case SyntaxKind . PropertySignature : case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : staticFlag &= getSyntacticModifierFlags ( searchSpaceNode ) ; searchSpaceNode = searchSpaceNode . parent ; break ; default : return undefined ; } const sourceFile = searchSpaceNode . getSourceFile ( ) ; const references = mapDefined ( getPossibleSymbolReferenceNodes ( sourceFile , "super" , searchSpaceNode ) , node => { if ( node . kind !== SyntaxKind . SuperKeyword ) { return ; } const container = getSuperContainer ( node , false ) ; return container && isStatic ( container ) === ! ! staticFlag && container . parent . symbol === searchSpaceNode . symbol ? nodeEntry ( node ) : undefined ; } ) ; return [ { definition : { type : DefinitionKind . Symbol , symbol : searchSpaceNode . symbol } , references } ] ; } function isParameterName ( node ) { return node . kind === SyntaxKind . Identifier && node . parent . kind === SyntaxKind . Parameter && ( node . parent as ParameterDeclaration ) . name === node ; } function getReferencesForThisKeyword ( thisOrSuperKeyword , sourceFiles , cancellationToken ) { let searchSpaceNode = getThisContainer ( thisOrSuperKeyword , false ) ; let staticFlag = ModifierFlags . Static ; switch ( searchSpaceNode . kind ) { case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : if ( isObjectLiteralMethod ( searchSpaceNode ) ) { staticFlag &= getSyntacticModifierFlags ( searchSpaceNode ) ; searchSpaceNode = searchSpaceNode . parent ; break ; } case SyntaxKind . PropertyDeclaration : case SyntaxKind . PropertySignature : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : staticFlag &= getSyntacticModifierFlags ( searchSpaceNode ) ; searchSpaceNode = searchSpaceNode . parent ; break ; case SyntaxKind . SourceFile : if ( isExternalModule ( searchSpaceNode as SourceFile ) || isParameterName ( thisOrSuperKeyword ) ) { return undefined ; } case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : break ; default : return undefined ; } const references = flatMap ( searchSpaceNode . kind === SyntaxKind . SourceFile ? sourceFiles : [ searchSpaceNode . getSourceFile ( ) ] , sourceFile => { cancellationToken . throwIfCancellationRequested ( ) ; return getPossibleSymbolReferenceNodes ( sourceFile , "this" , isSourceFile ( searchSpaceNode ) ? sourceFile : searchSpaceNode ) . filter ( node => { if ( ! isThis ( node ) ) { return false ; } const container = getThisContainer ( node , false ) ; switch ( searchSpaceNode . kind ) { case SyntaxKind . FunctionExpression : case SyntaxKind . FunctionDeclaration : return searchSpaceNode . symbol === container . symbol ; case SyntaxKind . MethodDeclaration : case SyntaxKind . MethodSignature : return isObjectLiteralMethod ( searchSpaceNode ) && searchSpaceNode . symbol === container . symbol ; case SyntaxKind . ClassExpression : case SyntaxKind . ClassDeclaration : case SyntaxKind . ObjectLiteralExpression : return container . parent && searchSpaceNode . symbol === container . parent . symbol && isStatic ( container ) === ! ! staticFlag ; case SyntaxKind . SourceFile : return container . kind === SyntaxKind . SourceFile && ! isExternalModule ( container as SourceFile ) && ! isParameterName ( node ) ; } } ) ; } ) . map ( n => nodeEntry ( n ) ) ; const thisParameter = firstDefined ( references , r => isParameter ( r . node . parent ) ? r . node : undefined ) ; return [ { definition : { type : DefinitionKind . This , node : thisParameter || thisOrSuperKeyword } , references } ] ; } function getReferencesForStringLiteral ( node , sourceFiles , checker , cancellationToken ) { const type = getContextualTypeFromParentOrAncestorTypeNode ( node , checker ) ; const references = flatMap ( sourceFiles , sourceFile => { cancellationToken . throwIfCancellationRequested ( ) ; return mapDefined ( getPossibleSymbolReferenceNodes ( sourceFile , node . text ) , ref => { if ( isStringLiteralLike ( ref ) && ref . text === node . text ) { if ( type ) { const refType = getContextualTypeFromParentOrAncestorTypeNode ( ref , checker ) ; if ( type !== checker . getStringType ( ) && type === refType ) { return nodeEntry ( ref , EntryKind . StringLiteral ) ; } } else { return isNoSubstitutionTemplateLiteral ( ref ) && ! rangeIsOnSingleLine ( ref , sourceFile ) ? undefined : nodeEntry ( ref , EntryKind . StringLiteral ) ; } } } ) ; } ) ; return [ { definition : { type : DefinitionKind . String , node } , references } ] ; } function populateSearchSymbolSet ( symbol , location , checker , isForRename , providePrefixAndSuffixText , implementations ) { const result = [ ] ; forEachRelatedSymbol < void > ( symbol , location , checker , isForRename , ! ( isForRename && providePrefixAndSuffixText ) , ( sym , root , base ) => { if ( base ) { if ( isStaticSymbol ( symbol ) !== isStaticSymbol ( base ) ) { base = undefined ; } } result . push ( base || root || sym ) ; } , ( ) => ! implementations ) ; return result ; } param allowBaseTypes function forEachRelatedSymbol < T > ( symbol , location , checker , isForRenamePopulateSearchSymbolSet , onlyIncludeBindingElementAtReferenceLocation , param baseSymbol cbSymbol , allowBaseTypes ) { const containingObjectLiteralElement = getContainingObjectLiteralElement ( location ) ; if ( containingObjectLiteralElement ) { const shorthandValueSymbol = checker . getShorthandAssignmentValueSymbol ( location . parent ) ; if ( shorthandValueSymbol && isForRenamePopulateSearchSymbolSet ) { return cbSymbol ( shorthandValueSymbol , undefined , undefined , EntryKind . SearchedLocalFoundProperty ) ; } const contextualType = checker . getContextualType ( containingObjectLiteralElement . parent ) ; const res = contextualType && firstDefined ( getPropertySymbolsFromContextualType ( containingObjectLiteralElement , checker , contextualType , true ) , sym => fromRoot ( sym , EntryKind . SearchedPropertyFoundLocal ) ) ; if ( res ) return res ; const propertySymbol = getPropertySymbolOfDestructuringAssignment ( location , checker ) ; const res1 = propertySymbol && cbSymbol ( propertySymbol , undefined , undefined , EntryKind . SearchedPropertyFoundLocal ) ; if ( res1 ) return res1 ; const res2 = shorthandValueSymbol && cbSymbol ( shorthandValueSymbol , undefined , undefined , EntryKind . SearchedLocalFoundProperty ) ; if ( res2 ) return res2 ; } const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration ( location , symbol , checker ) ; if ( aliasedSymbol ) { const res = cbSymbol ( aliasedSymbol , undefined , undefined , EntryKind . Node ) ; if ( res ) return res ; } const res = fromRoot ( symbol ) ; if ( res ) return res ; if ( symbol . valueDeclaration && isParameterPropertyDeclaration ( symbol . valueDeclaration , symbol . valueDeclaration . parent ) ) { const paramProps = checker . getSymbolsOfParameterPropertyDeclaration ( cast ( symbol . valueDeclaration , isParameter ) , symbol . name ) ; Debug . assert ( paramProps . length === 2 && ! ! ( paramProps [ 0 ] . flags & SymbolFlags . FunctionScopedVariable ) && ! ! ( paramProps [ 1 ] . flags & SymbolFlags . Property ) ) ; return fromRoot ( symbol . flags & SymbolFlags . FunctionScopedVariable ? paramProps [ 1 ] : paramProps [ 0 ] ) ; } const exportSpecifier = getDeclarationOfKind < ExportSpecifier > ( symbol , SyntaxKind . ExportSpecifier ) ; if ( ! isForRenamePopulateSearchSymbolSet || exportSpecifier && ! exportSpecifier . propertyName ) { const localSymbol = exportSpecifier && checker . getExportSpecifierLocalTargetSymbol ( exportSpecifier ) ; if ( localSymbol ) { const res = cbSymbol ( localSymbol , undefined , undefined , EntryKind . Node ) ; if ( res ) return res ; } } if ( ! isForRenamePopulateSearchSymbolSet ) { let bindingElementPropertySymbol ; if ( onlyIncludeBindingElementAtReferenceLocation ) { bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName ( location . parent ) ? getPropertySymbolFromBindingElement ( checker , location . parent ) : undefined ; } else { bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol , checker ) ; } return bindingElementPropertySymbol && fromRoot ( bindingElementPropertySymbol , EntryKind . SearchedPropertyFoundLocal ) ; } Debug . assert ( isForRenamePopulateSearchSymbolSet ) ; const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation ; if ( includeOriginalSymbolOfBindingElement ) { const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol , checker ) ; return bindingElementPropertySymbol && fromRoot ( bindingElementPropertySymbol , EntryKind . SearchedPropertyFoundLocal ) ; } function fromRoot ( sym , kind ? ) { return firstDefined ( checker . getRootSymbols ( sym ) , rootSymbol => cbSymbol ( sym , rootSymbol , undefined , kind ) || ( rootSymbol . parent && rootSymbol . parent . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) && allowBaseTypes ( rootSymbol ) ? getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . name , checker , base => cbSymbol ( sym , rootSymbol , base , kind ) ) : undefined ) ) ; } function getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol , checker ) { const bindingElement = getDeclarationOfKind < BindingElement > ( symbol , SyntaxKind . BindingElement ) ; if ( bindingElement && isObjectBindingElementWithoutPropertyName ( bindingElement ) ) { return getPropertySymbolFromBindingElement ( checker , bindingElement ) ; } } } param symbol param propertyName param result param previousIterationSymbolsCache function getPropertySymbolsFromBaseTypes < T > ( symbol , propertyName , checker , cb ) { const seen = new Map < SymbolId , true > ( ) ; return recur ( symbol ) ; function recur ( symbol ) { if ( ! ( symbol . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ) || ! addToSeen ( seen , getSymbolId ( symbol ) ) ) return ; return firstDefined ( symbol . declarations , declaration => firstDefined ( getAllSuperTypeNodes ( declaration ) , typeReference => { const type = checker . getTypeAtLocation ( typeReference ) ; const propertySymbol = type && type . symbol && checker . getPropertyOfType ( type , propertyName ) ; return type && propertySymbol && ( firstDefined ( checker . getRootSymbols ( propertySymbol ) , cb ) || recur ( type . symbol ) ) ; } ) ) ; } } interface RelatedSymbol { readonly symbol : Symbol ; readonly kind : NodeEntryKind | undefined ; } function isStaticSymbol ( symbol ) { if ( ! symbol . valueDeclaration ) return false ; const modifierFlags = getEffectiveModifierFlags ( symbol . valueDeclaration ) ; return ! ! ( modifierFlags & ModifierFlags . Static ) ; } function getRelatedSymbol ( search , referenceSymbol , referenceLocation , state ) { const { checker } = state ; return forEachRelatedSymbol ( referenceSymbol , referenceLocation , checker , false , state . options . use !== FindReferencesUse . Rename || ! ! state . options . providePrefixAndSuffixTextForRename , ( sym , rootSymbol , baseSymbol , kind ) : RelatedSymbol | undefined => { if ( baseSymbol ) { if ( isStaticSymbol ( referenceSymbol ) !== isStaticSymbol ( baseSymbol ) ) { baseSymbol = undefined ; } } return search . includes ( baseSymbol || rootSymbol || sym ) ? { symbol : rootSymbol && ! ( getCheckFlags ( sym ) & CheckFlags . Synthetic ) ? rootSymbol : sym , kind } : undefined ; } , rootSymbol => ! ( search . parents && ! search . parents . some ( parent => explicitlyInheritsFrom ( rootSymbol . parent ! , parent , state . inheritsFromCache , checker ) ) ) ) ; } /**
         * Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations
         * of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class
         * then we need to widen the search to include type positions as well.
         * On the contrary, if we are searching for "Bar" in type position and we trace bar to an interface, and an uninstantiated
         * module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
         * do not intersect in any of the three spaces.
         */ export function getIntersectingMeaningFromDeclarations ( node , symbol ) { let meaning = getMeaningFromLocation ( node ) ; const { declarations } = symbol ; if ( declarations ) { let lastIterationMeaning ; do { lastIterationMeaning = meaning ; for ( const declaration of declarations ) { const declarationMeaning = getMeaningFromDeclaration ( declaration ) ; if ( declarationMeaning & meaning ) { meaning |= declarationMeaning ; } } } while ( meaning !== lastIterationMeaning ) ; } return meaning ; } function isImplementation ( node ) { return ! ! ( node . flags & NodeFlags . Ambient ) ? ! ( isInterfaceDeclaration ( node ) || isTypeAliasDeclaration ( node ) ) : ( isVariableLike ( node ) ? hasInitializer ( node ) : isFunctionLikeDeclaration ( node ) ? ! ! node . body : isClassLike ( node ) || isModuleOrEnumDeclaration ( node ) ) ; } export function getReferenceEntriesForShorthandPropertyAssignment ( node , checker , addReference ) { const refSymbol = checker . getSymbolAtLocation ( node ) ! ; const shorthandSymbol = checker . getShorthandAssignmentValueSymbol ( refSymbol . valueDeclaration ) ; if ( shorthandSymbol ) { for ( const declaration of shorthandSymbol . getDeclarations ( ) ! ) { if ( getMeaningFromDeclaration ( declaration ) & SemanticMeaning . Value ) { addReference ( declaration ) ; } } } } function forEachDescendantOfKind ( node , kind , action ) { forEachChild ( node , child => { if ( child . kind === kind ) { action ( child ) ; } forEachDescendantOfKind ( child , kind , action ) ; } ) ; } /** Get `C` given `N` if `N` is in the position `class C extends N` or `class C extends foo.N` where `N` is an identifier. */ function tryGetClassByExtendingIdentifier ( node ) { return tryGetClassExtendingExpressionWithTypeArguments ( climbPastPropertyAccess ( node ) . parent ) ; } /**
         * If we are just looking for implementations and this is a property access expression, we need to get the
         * symbol of the local type of the symbol the property is being accessed on. This is because our search
         * symbol may have a different parent symbol if the local type's symbol does not declare the property
         * being accessed (i.e. it is declared in some parent class or interface)
         */ function getParentSymbolsOfPropertyAccess ( location , symbol , checker ) { const propertyAccessExpression = isRightSideOfPropertyAccess ( location ) ? location . parent as PropertyAccessExpression : undefined ; const lhsType = propertyAccessExpression && checker . getTypeAtLocation ( propertyAccessExpression . expression ) ; const res = mapDefined ( lhsType && ( lhsType . isUnionOrIntersection ( ) ? lhsType . types : lhsType . symbol === symbol . parent ? undefined : [ lhsType ] ) , t => t . symbol && t . symbol . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ? t . symbol : undefined ) ; return res . length === 0 ? undefined : res ; } function isForRenameWithPrefixAndSuffixText ( options ) { return options . use === FindReferencesUse . Rename && options . providePrefixAndSuffixTextForRename ; } } }