public getReferenceSiteInfo()

in src/documents/positionContexts/TemplatePositionContext.ts [113:253]


    public getReferenceSiteInfo(considerDefinitionItself: boolean): IReferenceSite | undefined {
        const tleInfo = this.tleInfo;
        if (tleInfo) {
            const scope = tleInfo.scope;
            const tleCharacterIndex = tleInfo.tleCharacterIndex;
            const definitionDocument = this.document;
            const referenceDocument = this.document;

            const tleFuncCall: TLE.FunctionCallValue | undefined = TLE.asFunctionCallValue(tleInfo.tleValue);
            if (tleFuncCall) {
                if (tleFuncCall.namespaceToken && tleFuncCall.namespaceToken.span.contains(tleCharacterIndex, ContainsBehavior.strict)) {
                    // Inside the namespace of a user-function reference
                    const ns = tleFuncCall.namespaceToken.stringValue;
                    const nsDefinition = scope.getFunctionNamespaceDefinition(ns);
                    if (nsDefinition) {
                        const unquotedReferenceSpan: Span = tleFuncCall.namespaceToken.span.translate(this.jsonTokenStartIndex);
                        return { referenceKind: ReferenceSiteKind.reference, referenceDocument, definition: nsDefinition, definitionScope: scope, unquotedReferenceSpan, definitionDocument };
                    }
                } else if (tleFuncCall.nameToken) {
                    const unquotedReferenceSpan: Span = tleFuncCall.nameToken.span.translate(this.jsonTokenStartIndex);
                    const referenceKind = ReferenceSiteKind.reference;

                    if (tleFuncCall.nameToken.span.contains(tleCharacterIndex, ContainsBehavior.strict)) {
                        if (tleFuncCall.namespaceToken) {
                            // Inside the name of a user-function reference
                            const ns = tleFuncCall.namespaceToken.stringValue;
                            const name = tleFuncCall.nameToken.stringValue;
                            const nsDefinition = scope.getFunctionNamespaceDefinition(ns);
                            const userFunctiondefinition = scope.getUserFunctionDefinition(ns, name);
                            if (nsDefinition && userFunctiondefinition) {
                                return { referenceKind, referenceDocument, definition: userFunctiondefinition, definitionScope: scope, unquotedReferenceSpan, definitionDocument };
                            }
                        } else {
                            // Inside a reference to a built-in function
                            const builtInFuncName: string = tleFuncCall.nameToken.stringValue.toLowerCase();

                            // If it's inside a 'parameters' or 'variables' function call, get a reference to the referenced param/var instead of the parameters/variables built-infunction
                            if (tleFuncCall.argumentExpressions.length === 1) {
                                const arg = tleFuncCall.argumentExpressions[0];
                                if (arg instanceof TLE.StringValue) {
                                    const argStringValue: string | undefined = tleFuncCall.argumentExpressions[0]?.asStringValue?.unquotedValue;
                                    if (argStringValue) {
                                        if (builtInFuncName === templateKeys.parameters) {
                                            const ref = this.getParameterReference(referenceDocument, definitionDocument, scope, referenceKind, arg);
                                            if (ref) {
                                                return ref;
                                            }
                                        } else if (builtInFuncName === templateKeys.variables) {
                                            const ref = this.getVariableReference(referenceDocument, definitionDocument, scope, referenceKind, arg);
                                            if (ref) {
                                                return ref;
                                            }
                                        }
                                    }
                                }
                            }
                            const functionMetadata: BuiltinFunctionMetadata | undefined = AzureRMAssets.getFunctionMetadataFromName(tleFuncCall.nameToken.stringValue);
                            if (functionMetadata) {
                                return { referenceKind, referenceDocument, definition: functionMetadata, definitionScope: undefined, unquotedReferenceSpan, definitionDocument };
                            }

                        }
                    }
                }
            }

            const tleStringValue: TLE.StringValue | undefined = TLE.asStringValue(tleInfo.tleValue);
            if (tleStringValue) {
                const referenceKind = ReferenceSiteKind.reference;

                if (tleStringValue.isParametersArgument()) {
                    // Inside the 'xxx' of a parameters('xxx') reference
                    const ref = this.getParameterReference(referenceDocument, definitionDocument, scope, referenceKind, tleStringValue);
                    if (ref) {
                        return ref;
                    }
                } else if (tleStringValue.isVariablesArgument()) {
                    const ref = this.getVariableReference(referenceDocument, definitionDocument, scope, referenceKind, tleStringValue);
                    if (ref) {
                        return ref;
                    }
                }
            }

            // Is it a parameter value for a nested or linked template?
            // Note that the scope of a parameter value doesn't (currently) match the scope
            // of the template that the parameter is defined in, e.g.:
            /*

                "resources": [
                {
                    "type": "Microsoft.Resources/deployments",
                    "properties": {
                        "parameters": {  <<<<<<<< Parameter value definition
                            "nestedParameter1": {
                                "value": "[parameters('topLevelParameter2')]"
                            }
                        },
                        "template": {
                            "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                            "contentVersion": "1.0.0.0",
                            "parameters": {
                                "nestedParameter1": {  <<<<<<<< Parameter definition
                                    "type": "string"
                                }
                            }
            */
            // Note that the value of nestedParameter1 is inside the top-level scope (in order to interpret
            //   expressions correctly in that scope).  So nestedParameter1 will have its definition inside
            //   the child deployment's scope, and we need to check there as well as the current scope.
            for (const childScope of scope.childScopes) {
                if (childScope.parameterValuesSource) {
                    const infoAsParamValue = getReferenceSiteInfoForParameterValue(
                        this.document,
                        childScope.parameterDefinitionsSource,
                        childScope,
                        childScope.parameterValuesSource,
                        this.documentCharacterIndex);
                    if (infoAsParamValue) {
                        return infoAsParamValue;
                    }
                }
            }

            if (considerDefinitionItself) {
                const definition = this.getDefinitionAtSite();
                if (definition && definition.nameValue) {
                    return {
                        referenceKind: ReferenceSiteKind.definition,
                        definition: definition,
                        referenceDocument: this.document,
                        definitionDocument: this.document,
                        definitionScope: tleInfo.scope,
                        unquotedReferenceSpan: definition.nameValue?.unquotedSpan
                    };
                }
            }

            return undefined;
        }
    }