import { CancellationToken } from 'vscode-languageserver' ; import { Declaration } from '../analyzer/declaration' ; import * as ParseTreeUtils from '../analyzer/parseTreeUtils' ; import { SourceMapper } from '../analyzer/sourceMapper' ; import { TypeEvaluator } from '../analyzer/typeEvaluatorTypes' ; import { throwIfCancellationRequested } from '../common/cancellationUtils' ; import { convertOffsetToPosition , convertPositionToOffset } from '../common/positionUtils' ; import { DocumentRange , Position } from '../common/textRange' ; import { TextRange } from '../common/textRange' ; import { NameNode , ParseNode , ParseNodeType } from '../parser/parseNodes' ; import { ParseResults } from '../parser/parser' ; import { DocumentSymbolCollector } from './documentSymbolCollector' ; export type ReferenceCallback = ( locations : DocumentRange [ ] ) => void ; export class ReferencesResult { private readonly _locations : DocumentRange [ ] = [ ] ; constructor ( readonly requiresGlobalSearch , readonly nodeAtOffset , readonly symbolName , readonly declarations , private readonly _reporter ? ) { } get locations ( ) : readonly DocumentRange [ ] { return this . _locations ; } addLocations ( ... locs ) { if ( locs . length === 0 ) { return ; } if ( this . _reporter ) { this . _reporter ( locs ) ; } this . _locations . push ( ... locs ) ; } } export class FindReferencesTreeWalker { constructor ( private _parseResults , private _filePath , private _referencesResult , private _includeDeclaration , private _evaluator , private _cancellationToken ) { } findReferences ( rootNode = this . _parseResults . parseTree ) { const collector = new DocumentSymbolCollector ( this . _referencesResult . symbolName , this . _referencesResult . declarations , this . _evaluator , this . _cancellationToken , rootNode , true ) ; const results = [ ] ; for ( const result of collector . collect ( ) ) { if ( this . _includeDeclaration || result . node !== this . _referencesResult . nodeAtOffset ) { results . push ( { path : this . _filePath , range : { start : convertOffsetToPosition ( result . range . start , this . _parseResults . tokenizerOutput . lines ) , end : convertOffsetToPosition ( TextRange . getEnd ( result . range ) , this . _parseResults . tokenizerOutput . lines ) , } , } ) ; } } return results ; } } export class ReferencesProvider { static getDeclarationForNode ( sourceMapper , filePath , node , evaluator , reporter , token ) { throwIfCancellationRequested ( token ) ; const declarations = DocumentSymbolCollector . getDeclarationsForNode ( node , evaluator , false , token , sourceMapper ) ; if ( declarations . length === 0 ) { return undefined ; } const requiresGlobalSearch = declarations . some ( ( decl ) => { if ( decl . path !== filePath ) { return true ; } const evalScope = ParseTreeUtils . getEvaluationScopeNode ( decl . node ) ; if ( evalScope . nodeType === ParseNodeType . Module || evalScope . nodeType === ParseNodeType . Class ) { return true ; } if ( decl . node ?. parent ?. nodeType === ParseNodeType . MemberAccess && decl . node === decl . node . parent . memberName ) { return true ; } return false ; } ) ; return new ReferencesResult ( requiresGlobalSearch , node , node . value , declarations , reporter ) ; } static getDeclarationForPosition ( sourceMapper , parseResults , filePath , position , evaluator , reporter , token ) { throwIfCancellationRequested ( token ) ; const offset = convertPositionToOffset ( position , parseResults . tokenizerOutput . lines ) ; if ( offset === undefined ) { return undefined ; } const node = ParseTreeUtils . findNodeByOffset ( parseResults . parseTree , offset ) ; if ( node === undefined ) { return undefined ; } if ( node . nodeType !== ParseNodeType . Name ) { return undefined ; } return this . getDeclarationForNode ( sourceMapper , filePath , node , evaluator , reporter , token ) ; } static addReferences ( parseResults , filePath , referencesResult , includeDeclaration , evaluator , token ) { const refTreeWalker = new FindReferencesTreeWalker ( parseResults , filePath , referencesResult , includeDeclaration , evaluator , token ) ; referencesResult . addLocations ( ... refTreeWalker . findReferences ( ) ) ; } }