/******************************************************************************
 * Copyright 2021 TypeFox GmbH
 * This program and the accompanying materials are made available under the
 * terms of the MIT License, which is available in the project root.
 ******************************************************************************/ import { findAssignment } from '../grammar/grammar-util' ; import { LangiumServices } from '../services' ; import { AstNode , CstNode , Reference } from '../syntax-tree' ; import { isReference } from '../utils/ast-util' ; import { findRelevantNode } from '../utils/cst-util' ; import { Stream } from '../utils/stream' ; import { ReferenceDescription } from '../workspace/ast-descriptions' ; import { AstNodeLocator } from '../workspace/ast-node-locator' ; import { IndexManager } from '../workspace/index-manager' ; import { NameProvider } from './naming' ; export interface References { param sourceCstNode findDeclaration ( sourceCstNode ) : CstNode | undefined ; param targetNode findReferences ( targetNode ) : Stream < ReferenceDescription > ; } export class DefaultReferences implements References { protected readonly nameProvider : NameProvider ; protected readonly index : IndexManager ; protected readonly nodeLocator : AstNodeLocator ; constructor ( services ) { this . nameProvider = services . references . NameProvider ; this . index = services . shared . workspace . IndexManager ; this . nodeLocator = services . index . AstNodeLocator ; } findDeclaration ( sourceCstNode ) { if ( sourceCstNode ) { const assignment = findAssignment ( sourceCstNode ) ; const nodeElem = findRelevantNode ( sourceCstNode ) ; if ( assignment && nodeElem ) { const reference = ( nodeElem as any ) [ assignment . feature ] as unknown ; if ( isReference ( reference ) ) { return this . processReference ( reference ) ; } else if ( Array . isArray ( reference ) ) { for ( const ref of reference ) { if ( isReference ( ref ) ) { const target = this . processReference ( ref ) ; if ( target && target . text === sourceCstNode . text ) return target ; } } } else { const nameNode = this . nameProvider . getNameNode ( nodeElem ) ; if ( nameNode === sourceCstNode || nameNode && nameNode . offset <= sourceCstNode . offset && nameNode . offset + nameNode . length > sourceCstNode . offset ) { return nameNode ; } } } } return undefined ; } findReferences ( targetNode ) { return this . index . findAllReferences ( targetNode , this . nodeLocator . getAstNodePath ( targetNode ) ) ; } protected processReference ( reference ) { const ref = reference . ref ; if ( ref && ref . $cstNode ) { const targetNode = this . nameProvider . getNameNode ( ref ) ; if ( ! targetNode ) { return ref . $cstNode ; } else { return targetNode ; } } return undefined ; } }