protected ILookupItem GetLookupElement(string replace, TextLookupRanges ranges)
        {
            var info = new TextualInfo(replace, replace)
            {
                ReplaceText = replace, Ranges = ranges
            };
            var item = LookupItemFactory.CreateLookupItem(info)
                       .WithPresentation(_ => new TextPresentation <TextualInfo>(info))
                       .WithBehavior(_ => new TextualBehavior <TextualInfo>(info))
                       .WithMatcher(_ => new TextualMatcher <TextualInfo>(info));

            return(item);
        }
        private static LookupItem <TextualInfo> CreateLookupItem([NotNull] IMethodDeclaration methodDeclaration, [NotNull] CSharpCodeCompletionContext context)
        {
            var typeParameterName = GetTypeParameterName(methodDeclaration);
            var textualInfo       = new TextualInfo(typeParameterName, typeParameterName, context.BasicContext)
            {
                Ranges = context.CompletionRanges
            };

            var lookupItem = LookupItemFactory.CreateLookupItem(textualInfo)
                             .WithPresentation(item =>
            {
                var presentation = new PostfixTemplatePresentation(typeParameterName);
                var grayText     = TextStyle.FromForeColor(Color.Gray);
                presentation.DisplayName.Append("*", grayText);
                presentation.DisplayTypeName = new RichText("(create type parameter)", grayText);
                return(presentation);
            })
                             .WithMatcher(item => new TextualMatcher <TextualInfo>(item.Info, IdentifierMatchingStyle.Default))
                             .WithBehavior(item => new TypeParameterFromUsageBehavior(item.Info));

            return(lookupItem);
        }
        private ILookupItem CreateMethodItem(CSharpCodeCompletionContext context,
                                             UnityEventFunction eventFunction, IClassLikeDeclaration declaration,
                                             bool hasReturnType, AccessRights accessRights)
        {
            if (CSharpLanguage.Instance == null)
            {
                return(null);
            }

            // Only show the modifier in the list text if it's not already specified and there isn't a return type, in
            // which case we default to `private`. E.g. if someone types `OnAnim`, then show `private void OnAnimate...`
            // but if they type `void OnAnim`, they don't want a modifier, and if they type `public void OnAnim` then
            // they want to use `public`
            var showModifier = false;

            if (!hasReturnType && accessRights == AccessRights.NONE)
            {
                showModifier = true;
                accessRights = AccessRights.PRIVATE;
            }

            // Note that we can't keep this declaration - it will become invalid as the user types to narrow down the
            // search and modifies the PSI file. This only affects ReSharper, Rider has different code completion
            // mechanism
            var factory           = CSharpElementFactory.GetInstance(declaration, false);
            var methodDeclaration = eventFunction.CreateDeclaration(factory, declaration, accessRights);

            if (methodDeclaration.DeclaredElement == null)
            {
                return(null);
            }

            // This is effectively the same as GenerateMemberPresentation, but without the overhead that comes
            // with the flexibility of formatting any time of declared element. We just hard code the format
            var predefinedType = context.PsiModule.GetPredefinedType();
            var parameters     = string.Empty;

            if (eventFunction.Parameters.Length > 0)
            {
                var sb = new StringBuilder();
                for (var i = 0; i < eventFunction.Parameters.Length; i++)
                {
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }

                    var parameter = eventFunction.Parameters[i];
                    var type      = predefinedType.TryGetType(parameter.ClrTypeName, NullableAnnotation.Unknown);
                    var typeName  = type?.GetPresentableName(CSharpLanguage.Instance) ??
                                    parameter.ClrTypeName.ShortName;
                    sb.AppendFormat("{0}{1}{2}", parameter.IsByRef ? "out" : string.Empty,
                                    typeName, parameter.IsArray ? "[]" : string.Empty);
                }
                parameters = sb.ToString();
            }
            var text            = $"{eventFunction.Name}({parameters})";
            var parameterOffset = eventFunction.Name.Length;

            var modifier = showModifier
                ? CSharpDeclaredElementPresenter.Instance.Format(accessRights) + " "
                : string.Empty;

            var psiIconManager = context.BasicContext.LookupItemsOwner.Services.PsiIconManager;

            // Note that because this is a text based lookup item, then it won't be included if the normal C# method
            // filter is applied. We can't make it a method based lookup item because the DeclaredElement isn't valid in
            // this situation - it's not a real method, and a DeclaredElementInfo would try to store a pointer to it,
            // and be unable to recreate it when it's needed.
            var textualInfo = new TextualInfo(text, text)
            {
                Ranges = context.CompletionRanges
            };

            var lookupItem = LookupItemFactory.CreateLookupItem(textualInfo)
                             .WithPresentation(item =>
            {
                var displayName = new RichText($"{modifier}{text} {{ ... }}");

                // GenerateMemberPresentation marks everything as bold, and the parameters + block syntax as not important
                var parameterStartOffset = modifier.Length + parameterOffset;
                LookupUtil.MarkAsNotImportant(displayName,
                                              TextRange.FromLength(parameterStartOffset, displayName.Length - parameterStartOffset));
                LookupUtil.AddEmphasize(displayName, new TextRange(modifier.Length, displayName.Length));

                var image = psiIconManager.GetImage(CLRDeclaredElementType.METHOD);
                psiIconManager.AttachExtensions(image, GetAccessExtensions(accessRights));
                var marker = item.Info.Ranges.CreateVisualReplaceRangeMarker();
                return(new SimplePresentation(displayName, image, marker));
            })
                             .WithBehavior(_ => new UnityEventFunctionBehavior(myShellLocks, textualInfo, eventFunction, accessRights))
                             .WithMatcher(_ =>
                                          new ShiftedDeclaredElementMatcher(eventFunction.Name, modifier.Length, textualInfo));

            var description = GetDescription(context, methodDeclaration);

            return(new WrappedLookupItem(lookupItem, description));
        }