TextLookupRanges ComputeMemberReplaceRanges()

in resharper/resharper-unity/src/Unity/CSharp/Feature/Services/CodeCompletion/UnityEventFunctionRule.cs [735:860]


            TextLookupRanges ComputeMemberReplaceRanges(TreeOffset startOffset)
            {
                foreach (var treeNode in context.NodeInFile.ContainingNodes(returnThis: true))
                {
                    if (IsDeclarationToReplace(treeNode))
                    {
                        return RangesForDeclaration(treeNode);
                    }

                    if (treeNode.IsFiltered())
                    {
                        var prevMeaningfulSibling = treeNode.GetPreviousMeaningfulSiblingThroughWhitespaceAndComments();
                        if (prevMeaningfulSibling != null
                            && IsDeclarationToReplace(prevMeaningfulSibling)
                            && (!startOffset.IsValid() || prevMeaningfulSibling.GetTreeStartOffset() >= startOffset))
                        {
                            return RangesForDeclaration(prevMeaningfulSibling);
                        }

                        var nextMeaningfulSibling = treeNode.GetNextMeaningfulSibling();
                        if (nextMeaningfulSibling != null && IsDeclarationToReplace(nextMeaningfulSibling))
                        {
                            return RangesForDeclaration(nextMeaningfulSibling);
                        }
                    }

                    if (treeNode is IFieldDeclaration field)
                    {
                        var range = context.CompletionRanges.ReplaceRange;
                        if (field.GetPreviousMeaningfulSibling() is ITypeUsage typeUsage)
                        {
                            range = range.SetStartTo(typeUsage.GetDocumentStartOffset());
                        }

                        return new TextLookupRanges(range, range);
                    }

                    if (treeNode is ICSharpTypeMemberDeclaration)
                    {
                        return context.CompletionRanges;
                    }
                }

                return null;

                TextLookupRanges RangesForDeclaration(ITreeNode treeNode)
                {
                    var elementRange = ComputeReplaceRangeForDeclaration(treeNode);
                    if (!elementRange.IsValid()) return null;

                    return CodeCompletionContextProviderBase.GetTextLookupRanges(context.BasicContext, elementRange);
                }

                DocumentRange ComputeReplaceRangeForDeclaration(ITreeNode declaration)
                {
                    var startOffsetRange = new DocumentRange(GetDeclarationStartDocumentOffset(declaration));
                    var selectedRange = context.BasicContext.SelectedRange;

                    var anchorDeclaration = GetAnchorDeclaration(declaration);

                    var elementRange = startOffsetRange.Join(selectedRange)
                        .JoinRight(new DocumentRange(anchorDeclaration.GetDocumentEndOffset()));
                    if (!elementRange.IsValid())
                    {
                        elementRange = startOffsetRange.Join(selectedRange);
                    }

                    if (!elementRange.IsValid()) return DocumentRange.InvalidRange;

                    var anchorDeclarationNameRange = GetDeclarationNameRange(anchorDeclaration);
                    if (anchorDeclarationNameRange.IsValid())
                    {
                        var declarationNameLine = anchorDeclarationNameRange.StartOffset.ToDocumentCoords().Line;
                        var selectionLine = selectedRange.EndOffset.ToDocumentCoords().Line;
                        if (declarationNameLine != selectionLine)
                        {
                            return elementRange.SetEndTo(selectedRange.EndOffset);
                        }
                    }

                    return elementRange;
                }

                DocumentOffset GetDeclarationStartDocumentOffset(ITreeNode declaration)
                {
                    // note: do not include attributes into member range
                    var firstChild = declaration.GetNextMeaningfulChild(null);
                    if (firstChild is IDocCommentBlock)
                        firstChild = firstChild.GetNextMeaningfulSibling();

                    if (firstChild is IAttributeSectionList)
                        firstChild = firstChild.GetNextMeaningfulSibling();

                    return (firstChild ?? declaration).GetDocumentStartOffset();
                }

                ITreeNode GetAnchorDeclaration(ITreeNode declaration)
                {
                    if (declaration is IMethodDeclaration unfinishedMethod
                        && unfinishedMethod.NameIdentifier == null
                        && unfinishedMethod.LPar == null
                        && unfinishedMethod.ModifiersList == null
                        && unfinishedMethod.TypeUsage != null)
                    {
                        var nextDeclaration = unfinishedMethod.GetNextMeaningfulSibling();

                        if (IsDeclarationToReplace(nextDeclaration))
                            return nextDeclaration;
                    }

                    return declaration;
                }

                DocumentRange GetDeclarationNameRange(ITreeNode declaration)
                {
                    switch (declaration)
                    {
                        case IMultipleFieldDeclaration fieldDecl:
                            return fieldDecl.DeclaratorsEnumerable.FirstOrDefault().GetDocumentRange();
                        case IDeclaration decl:
                            return decl.GetNameDocumentRange();
                        default:
                            return declaration.GetDocumentRange();
                    }
                }
            }