private void TryLinkToRealReference(ISymbol typeSymbol, DocumentData documentData, ReferenceLocation refLocation)
        {
            if (typeSymbol.Kind != SymbolKind.NamedType)
            {
                return;
            }
            // A cref/nameof can be on a method or type trivia but we get always the type symbol
            var typeData = documentData.GetAllTypeDatas(o => o.Symbol.Equals(typeSymbol)).FirstOrDefault();

            if (typeData == null)
            {
                return;
            }
            // Try to find the real node where the cref/nameof is located
            var referenceNameNode   = typeData.Node.GetSimpleName(refLocation.Location.SourceSpan, true);
            var referenceSymbolInfo = documentData.SemanticModel.GetSymbolInfo(referenceNameNode);
            var data = documentData.GetNearestNodeData(referenceNameNode.Parent, referenceNameNode.IsInsideCref());

            if (referenceSymbolInfo.Symbol is IMethodSymbol methodSymbol)
            {
                if (!referenceNameNode.IsInsideCref())
                {
                    return;
                }
                var referenceData = ProjectData.GetFunctionData(methodSymbol);
                var reference     = new CrefFunctionDataReference(data, refLocation, referenceNameNode, methodSymbol, referenceData, false);
                data.References.TryAdd(reference);
                referenceData?.SelfReferences.TryAdd(reference);
            }
            else if (referenceNameNode.IsInsideNameOf())            // GetSymbolInfo will never return a concrete symbol for nameof only candidates
            {
                var referencedFuncs = new Dictionary <IMethodSymbol, FunctionData>();
                foreach (var candidateSymbol in referenceSymbolInfo.CandidateSymbols.OfType <IMethodSymbol>())
                {
                    var nameofReferenceData = ProjectData.GetFunctionData(candidateSymbol);
                    referencedFuncs.Add(candidateSymbol, nameofReferenceData);
                }
                var nameofReference = new NameofFunctionDataReference(data, refLocation, referenceNameNode, referencedFuncs, false);
                data.References.TryAdd(nameofReference);
                foreach (var referencedFun in referencedFuncs.Values.Where(o => o != null))
                {
                    referencedFun.SelfReferences.TryAdd(nameofReference);
                }
            }
        }
        private async Task ScanAllMethodReferenceLocations(IMethodSymbol methodSymbol, int depth, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (cancellationToken.IsCancellationRequested)
            {
                cancellationToken.ThrowIfCancellationRequested();
            }
            methodSymbol = methodSymbol.OriginalDefinition;
            if ((!_configuration.SearchForMethodReferences(methodSymbol) && !_mustScanForMethodReferences.Contains(methodSymbol)) ||
                !_searchedMethodReferences.TryAdd(methodSymbol))
            {
                return;
            }
            // FindReferencesAsync will not search just for the passed method symbol but also for all its overrides, interfaces and external interfaces
            // so we need to add all related symbols to the searched list in order to avoid scanning those related members in the future calls
            // If any of the related symbols was already searched then we know that all references of the current method were already found
            var alreadyScanned = false;

            foreach (var relatedMethod in GetAllRelatedMethods(methodSymbol))
            {
                if (!_searchedMethodReferences.TryAdd(relatedMethod))
                {
                    alreadyScanned = true;
                }
            }
            if (alreadyScanned)
            {
                return;
            }

            var references = await SymbolFinder.FindReferencesAsync(methodSymbol, _solution, _analyzeDocuments, cancellationToken).ConfigureAwait(false);

            depth++;
            if (depth > _maxScanningDepth)
            {
                _maxScanningDepth = depth;
            }
            foreach (var refLocation in references.SelectMany(o => o.Locations))
            {
                if (_scannedLocationsSymbols.Contains(refLocation))
                {
                    continue;
                }
                _scannedLocationsSymbols.TryAdd(refLocation);

                if (refLocation.Document.Project != ProjectData.Project)
                {
                    throw new InvalidOperationException($"Reference {refLocation} is located in a document from another project");
                }

                var documentData = ProjectData.GetDocumentData(refLocation.Document);
                if (documentData == null)
                {
                    continue;
                }
                var symbol = documentData.GetEnclosingSymbol(refLocation);
                if (symbol == null)
                {
                    documentData.AddDiagnostic($"Symbol not found for reference ${refLocation}", DiagnosticSeverity.Hidden);
                    continue;
                }

                if (symbol.Kind != SymbolKind.Method)
                {
                    TryLinkToRealReference(symbol, documentData, refLocation);
                    continue;
                }

                var baseMethodData = documentData.GetFunctionData(symbol);
                if (baseMethodData == null)                 // TODO: Current is null for lambda in fields
                {
                    var refMethodSymbol = (IMethodSymbol)symbol;
                    if (refMethodSymbol.MethodKind == MethodKind.AnonymousFunction || refMethodSymbol.MethodKind == MethodKind.LambdaMethod)
                    {
                        documentData.AddDiagnostic(
                            $"Function inside member {refMethodSymbol.ContainingSymbol} cannot be async because of its kind {refMethodSymbol.MethodKind}",
                            DiagnosticSeverity.Hidden);
                    }
                    else
                    {
                        documentData.AddDiagnostic(
                            $"Method {refMethodSymbol} cannot be async because of its kind {refMethodSymbol.MethodKind}",
                            DiagnosticSeverity.Hidden);
                    }
                    continue;
                }

                // Find the real method on that reference as FindReferencesAsync will also find references to base and interface methods
                // Save the reference as it can be made async
                var nameNode = baseMethodData.GetNode().GetSimpleName(refLocation.Location.SourceSpan);
                if (nameNode == null)
                {
                    continue;                     // Can happen for a foreach token
                }
                var referenceSymbolInfo   = documentData.SemanticModel.GetSymbolInfo(nameNode);
                var referenceSymbol       = referenceSymbolInfo.Symbol;
                var methodReferenceSymbol = referenceSymbol as IMethodSymbol;
                if (methodReferenceSymbol == null && referenceSymbol is IPropertySymbol propertyReferenceSymbol)
                {
                    // We need to find the usage of the property, if getter or setter is used
                    methodReferenceSymbol = nameNode.IsAssigned()
                                                ? propertyReferenceSymbol.SetMethod
                                                : propertyReferenceSymbol.GetMethod;
                }
                if (methodReferenceSymbol == null)
                {
                    // Check if the node is inside a nameof keyword as GetSymbolInfo will never return a symbol for it only candidates
                    if (nameNode.IsInsideNameOf())
                    {
                        var referencedFuncs = new Dictionary <IMethodSymbol, FunctionData>();
                        foreach (var candidateSymbol in referenceSymbolInfo.CandidateSymbols.OfType <IMethodSymbol>())
                        {
                            var nameofReferenceData = ProjectData.GetFunctionData(candidateSymbol);
                            referencedFuncs.Add(candidateSymbol, nameofReferenceData);
                        }
                        var nameofReference = new NameofFunctionDataReference(baseMethodData, refLocation, nameNode, referencedFuncs, true);
                        if (!baseMethodData.References.TryAdd(nameofReference))
                        {
                            _logger.Debug($"Performance hit: MembersReferences {nameNode} already added");
                        }
                        foreach (var referencedFun in referencedFuncs.Values.Where(o => o != null))
                        {
                            referencedFun.SelfReferences.TryAdd(nameofReference);
                        }
                        continue;
                    }

                    methodReferenceSymbol = TryFindCandidate(nameNode, referenceSymbolInfo, documentData.SemanticModel);
                    if (methodReferenceSymbol == null)
                    {
                        throw new InvalidOperationException($"Unable to find symbol for node {nameNode} inside function {baseMethodData.Symbol}");
                    }
                    documentData.AddDiagnostic(
                        $"GetSymbolInfo did not successfully resolved symbol for node {nameNode} inside function " +
                        $"{baseMethodData.Symbol.Name} {baseMethodData.GetLineSpan().Span.Format()}, " +
                        $"but we got a candidate instead. CandidateReason: {referenceSymbolInfo.CandidateReason}",
                        DiagnosticSeverity.Info);
                }
                var referenceFunctionData = ProjectData.GetFunctionData(methodReferenceSymbol);
                // Check if the reference is a cref reference or a nameof
                if (nameNode.IsInsideCref())
                {
                    var crefReference = new CrefFunctionDataReference(baseMethodData, refLocation, nameNode, methodReferenceSymbol, referenceFunctionData, true);
                    if (!baseMethodData.References.TryAdd(crefReference))
                    {
                        _logger.Debug($"Performance hit: MembersReferences {nameNode} already added");
                    }
                    referenceFunctionData?.SelfReferences.TryAdd(crefReference);
                    continue;                     // No need to further scan a cref reference
                }
                var methodReferenceData = new BodyFunctionDataReference(baseMethodData, refLocation, nameNode, methodReferenceSymbol, referenceFunctionData);
                if (!baseMethodData.References.TryAdd(methodReferenceData))
                {
                    _logger.Debug($"Performance hit: method reference {methodReferenceSymbol} already processed");
                    continue;                     // Reference already processed
                }
                referenceFunctionData?.SelfReferences.TryAdd(methodReferenceData);

                if (baseMethodData.Conversion == MethodConversion.Ignore)
                {
                    continue;
                }
                // Do not scan for method that will be only copied (e.g. the containing type is a new type).
                if (baseMethodData.Conversion == MethodConversion.Copy)
                {
                    continue;
                }

                if (baseMethodData is MethodOrAccessorData methodData && !_scannedMethodOrAccessors.Contains(methodData))
                {
                    await ScanMethodData(methodData, depth, cancellationToken).ConfigureAwait(false);
                }
                // Scan a local/anonymous function only if there is a chance that can be called elsewere. (e.g. saved to a variable or local function)
                // TODO: support local variables
                if (baseMethodData is LocalFunctionData)
                {
                    await ScanAllMethodReferenceLocations(baseMethodData.Symbol, depth, cancellationToken).ConfigureAwait(false);
                }
            }
        }
 private void AnalyzeNameofMethodReference(DocumentData documentData, MethodOrAccessorData methoData, NameofFunctionDataReference nameofData)
 {
     nameofData.RelatedBodyFunctionReferences.AddRange(
         methoData.BodyFunctionReferences.Where(o => o.ReferenceSymbol.Equals(nameofData.ReferenceSymbol)));
 }