Ejemplo n.º 1
0
        public Task <LanguageServer.Protocol.CompletionItem[]> HandleAsync(object input, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            // The VS LSP client supports streaming using IProgress<T> on various requests.
            // However, this works through liveshare on the LSP client, but not the LSP extension.
            // see https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1107682 for tracking.
            var request = ((JObject)input).ToObject <CompletionParams>(s_jsonSerializer);
            var context = new LSP.RequestContext(requestContext.GetClientCapabilities(), null);

            return(base.HandleRequestAsync(request, context, cancellationToken));
        }
Ejemplo n.º 2
0
        public async Task <InitializeResult> HandleAsync(InitializeParams param, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var context          = new LSP.RequestContext(requestContext.GetClientCapabilities(), null);
            var initializeResult = await base.HandleRequestAsync(param, context, cancellationToken).ConfigureAwait(false);

            initializeResult.Capabilities.Experimental = new RoslynExperimentalCapabilities {
                SyntacticLspProvider = true
            };
            return(initializeResult);
        }
Ejemplo n.º 3
0
        public async Task <SymbolInformation[]> HandleAsync(DocumentSymbolParams param, RequestContext <Solution> requestContext, CancellationToken cancellationToken)
        {
            var clientCapabilities = requestContext.GetClientCapabilities();

            if (clientCapabilities.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true)
            {
                // If the value is true, set it to false.  Liveshare does not support hierarchical document symbols.
                clientCapabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = false;
            }

            var context  = new LSP.RequestContext(clientCapabilities, null);
            var response = await base.HandleRequestAsync(param, context, cancellationToken).ConfigureAwait(false);

            // Since hierarchicalSupport will never be true, it is safe to cast the response to SymbolInformation[]
            return(response.Cast <SymbolInformation>().ToArray());
        }
Ejemplo n.º 4
0
 public override Task <LSP.Location[]> HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
 => GetDefinitionAsync(request, typeOnly: false, context, cancellationToken);
Ejemplo n.º 5
0
        public override async Task<WorkspaceEdit?> HandleRequestAsync(RenameParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;
            if (document != null)
            {
                var oldSolution = document.Project.Solution;
                var renameService = document.Project.LanguageServices.GetRequiredService<IEditorInlineRenameService>();
                var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

                var renameInfo = await renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);
                if (!renameInfo.CanRename)
                {
                    return null;
                }

                var renameLocationSet = await renameInfo.FindRenameLocationsAsync(oldSolution.Workspace.Options, cancellationToken).ConfigureAwait(false);
                var renameReplacementInfo = await renameLocationSet.GetReplacementsAsync(request.NewName, oldSolution.Workspace.Options, cancellationToken).ConfigureAwait(false);

                var renamedSolution = renameReplacementInfo.NewSolution;
                var solutionChanges = renamedSolution.GetChanges(oldSolution);

                // Linked files can correspond to multiple roslyn documents each with changes.  Merge the changes in the linked files so that all linked documents have the same text.
                // Then we can just take the text changes from the first document to avoid returning duplicate edits.
                renamedSolution = await renamedSolution.WithMergedLinkedFileChangesAsync(oldSolution, solutionChanges, cancellationToken: cancellationToken).ConfigureAwait(false);
                solutionChanges = renamedSolution.GetChanges(oldSolution);
                var changedDocuments = solutionChanges
                    .GetProjectChanges()
                    .SelectMany(p => p.GetChangedDocuments(onlyGetDocumentsWithTextChanges: true))
                    .GroupBy(docId => renamedSolution.GetRequiredDocument(docId).FilePath, StringComparer.OrdinalIgnoreCase).Select(group => group.First());

                var textDiffService = renamedSolution.Workspace.Services.GetRequiredService<IDocumentTextDifferencingService>();

                var documentEdits = await ProtocolConversions.ChangedDocumentsToTextDocumentEditsAsync(changedDocuments, renamedSolution.GetRequiredDocument, oldSolution.GetRequiredDocument,
                    textDiffService, cancellationToken).ConfigureAwait(false);

                return new WorkspaceEdit { DocumentChanges = documentEdits };
            }

            return null;
        }
Ejemplo n.º 6
0
        public async Task <LSP.CompletionList?> HandleRequestAsync(LSP.CompletionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            // C# and VB share the same LSP language server, and thus share the same default trigger characters.
            // We need to ensure the trigger character is valid in the document's language. For example, the '{'
            // character, while a trigger character in VB, is not a trigger character in C#.
            if (request.Context != null &&
                request.Context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter &&
                !char.TryParse(request.Context.TriggerCharacter, out var triggerCharacter) &&
                !char.IsLetterOrDigit(triggerCharacter) &&
                !IsValidTriggerCharacterForDocument(document, triggerCharacter))
            {
                return(null);
            }

            var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var completionOptions = await GetCompletionOptionsAsync(document, cancellationToken).ConfigureAwait(false);

            var completionService = document.Project.LanguageServices.GetRequiredService <CompletionService>();

            // TO-DO: More LSP.CompletionTriggerKind mappings are required to properly map to Roslyn CompletionTriggerKinds.
            // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1178726
            var completionTrigger = await ProtocolConversions.LSPToRoslynCompletionTriggerAsync(request.Context, document, position, cancellationToken).ConfigureAwait(false);

            var list = await completionService.GetCompletionsAsync(document, position, completionTrigger, options : completionOptions, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (list == null || list.Items.IsEmpty)
            {
                return(null);
            }

            var lspVSClientCapability     = context.ClientCapabilities.HasVisualStudioLspCapability() == true;
            var snippetsSupported         = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.SnippetSupport ?? false;
            var commitCharactersRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, ImmutableArray <string> >();

            // Cache the completion list so we can avoid recomputation in the resolve handler
            var resultId = await _completionListCache.UpdateCacheAsync(list, cancellationToken).ConfigureAwait(false);

            // Feature flag to enable the return of TextEdits instead of InsertTexts (will increase payload size).
            // Flag is defined in VisualStudio\Core\Def\PackageRegistration.pkgdef.
            // We also check against the CompletionOption for test purposes only.
            Contract.ThrowIfNull(context.Solution);
            var featureFlagService = context.Solution.Workspace.Services.GetRequiredService <IExperimentationService>();
            var returnTextEdits    = featureFlagService.IsExperimentEnabled(WellKnownExperimentNames.LSPCompletion) ||
                                     completionOptions.GetOption(CompletionOptions.ForceRoslynLSPCompletionExperiment, document.Project.Language);

            SourceText?documentText = null;
            TextSpan?  defaultSpan  = null;

            LSP.Range?defaultRange = null;
            if (returnTextEdits)
            {
                // We want to compute the document's text just once.
                documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

                // We use the first item in the completion list as our comparison point for span
                // and range for optimization when generating the TextEdits later on.
                var completionChange = await completionService.GetChangeAsync(
                    document, list.Items.First(), cancellationToken : cancellationToken).ConfigureAwait(false);

                // If possible, we want to compute the item's span and range just once.
                // Individual items can override this range later.
                defaultSpan  = completionChange.TextChange.Span;
                defaultRange = ProtocolConversions.TextSpanToRange(defaultSpan.Value, documentText);
            }

            var stringBuilder = new StringBuilder();

            using var _ = ArrayBuilder <LSP.CompletionItem> .GetInstance(out var lspCompletionItems);

            foreach (var item in list.Items)
            {
                var lspCompletionItem = await CreateLSPCompletionItemAsync(
                    request, document, item, resultId, lspVSClientCapability, completionTrigger, commitCharactersRuleCache,
                    completionService, context.ClientName, returnTextEdits, snippetsSupported, stringBuilder, documentText,
                    defaultSpan, defaultRange, cancellationToken).ConfigureAwait(false);

                lspCompletionItems.Add(lspCompletionItem);
            }

            return(new LSP.VSCompletionList
            {
                Items = lspCompletionItems.ToArray(),
                SuggestionMode = list.SuggestionModeItem != null,
            });

            // Local functions
            bool IsValidTriggerCharacterForDocument(Document document, char triggerCharacter)
            {
                if (document.Project.Language == LanguageNames.CSharp)
                {
                    return(_csharpTriggerCharacters.Contains(triggerCharacter));
                }
                else if (document.Project.Language == LanguageNames.VisualBasic)
                {
                    return(_vbTriggerCharacters.Contains(triggerCharacter));
                }

                // Typescript still calls into this for completion.
                // Since we don't know what their trigger characters are, just return true.
                return(true);
            }
Ejemplo n.º 7
0
        public async Task <object[]> HandleRequestAsync(DocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);

            var navBarService = document.Project.LanguageServices.GetRequiredService <INavigationBarItemService>();
            var navBarItems   = await navBarService.GetItemsAsync(document, supportsCodeGeneration : false, forceFrozenPartialSemanticsForCrossProcessOperations : false, cancellationToken).ConfigureAwait(false);

            if (navBarItems.IsEmpty)
            {
                return(Array.Empty <object>());
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            // TODO - Return more than 2 levels of symbols.
            // https://github.com/dotnet/roslyn/projects/45#card-20033869
            using var _ = ArrayBuilder <object> .GetInstance(out var symbols);

            if (context.ClientCapabilities?.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true)
            {
                // only top level ones
                foreach (var item in navBarItems)
                {
                    symbols.AddIfNotNull(GetDocumentSymbol(item, text, cancellationToken));
                }
            }
            else
            {
                foreach (var item in navBarItems)
                {
                    symbols.AddIfNotNull(GetSymbolInformation(item, document, text, containerName: null));

                    foreach (var childItem in item.ChildItems)
                    {
                        symbols.AddIfNotNull(GetSymbolInformation(childItem, document, text, item.Text));
                    }
                }
            }

            var result = symbols.ToArray();

            return(result);
        }
 public abstract Task <ResponseType> HandleRequestAsync(RequestType request, RequestContext context, CancellationToken cancellationToken);
Ejemplo n.º 9
0
        public override async Task <object[]> HandleRequestAsync(DocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(Array.Empty <SymbolInformation>());
            }

            var symbols = ArrayBuilder <object> .GetInstance();

            var navBarService = document.Project.LanguageServices.GetRequiredService <INavigationBarItemService>();
            var navBarItems   = await navBarService.GetItemsAsync(document, cancellationToken).ConfigureAwait(false);

            if (navBarItems.Count == 0)
            {
                return(symbols.ToArrayAndFree());
            }

            var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            // TODO - Return more than 2 levels of symbols.
            // https://github.com/dotnet/roslyn/projects/45#card-20033869
            if (context.ClientCapabilities?.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true)
            {
                foreach (var item in navBarItems)
                {
                    // only top level ones
                    symbols.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, cancellationToken).ConfigureAwait(false));
                }
            }
            else
            {
                foreach (var item in navBarItems)
                {
                    symbols.Add(GetSymbolInformation(item, compilation, tree, document, text, cancellationToken, containerName: null));

                    foreach (var childItem in item.ChildItems)
                    {
                        symbols.Add(GetSymbolInformation(childItem, compilation, tree, document, text, cancellationToken, item.Text));
                    }
                }
            }

            var result = symbols.WhereNotNull().ToArray();

            symbols.Free();
            return(result);
        }
Ejemplo n.º 10
0
        public override async Task <LSP.Location[]> HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var locations = ArrayBuilder <LSP.Location> .GetInstance();

            var document = context.Document;

            if (document == null)
            {
                return(locations.ToArrayAndFree());
            }

            var findUsagesService = document.Project.LanguageServices.GetRequiredService <IFindUsagesServiceRenameOnceTypeScriptMovesToExternalAccess>();
            var position          = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);

            var findUsagesContext = new SimpleFindUsagesContext(cancellationToken);

            await FindImplementationsAsync(findUsagesService, document, position, findUsagesContext).ConfigureAwait(false);

            foreach (var definition in findUsagesContext.GetDefinitions())
            {
                var text = definition.GetClassifiedText();
                foreach (var sourceSpan in definition.SourceSpans)
                {
                    if (context.ClientCapabilities?.HasVisualStudioLspCapability() == true)
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false));
                    }
                    else
                    {
                        locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            return(locations.ToArrayAndFree());
        }
Ejemplo n.º 11
0
        public override async Task <FoldingRange[]?> HandleRequestAsync(FoldingRangeParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var blockStructureService = document.Project.LanguageServices.GetService <BlockStructureService>();

            if (blockStructureService == null)
            {
                return(Array.Empty <FoldingRange>());
            }

            var blockStructure = await blockStructureService.GetBlockStructureAsync(document, cancellationToken).ConfigureAwait(false);

            if (blockStructure == null)
            {
                return(Array.Empty <FoldingRange>());
            }

            var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            return(GetFoldingRanges(blockStructure, text));
        }
        public async Task <LSP.DocumentOnAutoInsertResponseItem?> HandleRequestAsync(LSP.DocumentOnAutoInsertParams autoInsertParams, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            if (document == null)
            {
                return(null);
            }

            var service = document.GetRequiredLanguageService <IDocumentationCommentSnippetService>();

            // The editor calls this handler for C# and VB comment characters, but we only need to process the one for the language that matches the document
            if (autoInsertParams.Character == "\n" || autoInsertParams.Character == service.DocumentationCommentCharacter)
            {
                var documentationCommentResponse = await GetDocumentationCommentResponseAsync(autoInsertParams, document, service, cancellationToken).ConfigureAwait(false);

                if (documentationCommentResponse != null)
                {
                    return(documentationCommentResponse);
                }
            }

            // Only support this for razor as LSP doesn't support overtype yet.
            // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1165179/
            // Once LSP supports overtype we can move all of brace completion to LSP.
            if (autoInsertParams.Character == "\n" && context.ClientName == document.Services.GetService <DocumentPropertiesService>()?.DiagnosticsLspClientName)
            {
                var braceCompletionAfterReturnResponse = await GetBraceCompletionAfterReturnResponseAsync(autoInsertParams, document, cancellationToken).ConfigureAwait(false);

                if (braceCompletionAfterReturnResponse != null)
                {
                    return(braceCompletionAfterReturnResponse);
                }
            }

            return(null);
        }
 public override Task <TextEdit[]> HandleRequestAsync(DocumentRangeFormattingParams request, RequestContext context, CancellationToken cancellationToken)
 => GetTextEditsAsync(context, cancellationToken, range: request.Range);
Ejemplo n.º 14
0
        public async Task <LSP.CompletionList?> HandleRequestAsync(LSP.CompletionParams request, RequestContext context, CancellationToken cancellationToken)
        {
            var document = context.Document;

            Contract.ThrowIfNull(document);
            Contract.ThrowIfNull(context.Solution);

            // C# and VB share the same LSP language server, and thus share the same default trigger characters.
            // We need to ensure the trigger character is valid in the document's language. For example, the '{'
            // character, while a trigger character in VB, is not a trigger character in C#.
            if (request.Context != null &&
                request.Context.TriggerKind == LSP.CompletionTriggerKind.TriggerCharacter &&
                !char.TryParse(request.Context.TriggerCharacter, out var triggerCharacter) &&
                !char.IsLetterOrDigit(triggerCharacter) &&
                !IsValidTriggerCharacterForDocument(document, triggerCharacter))
            {
                return(null);
            }

            var completionOptions = GetCompletionOptions(document) with {
                UpdateImportCompletionCacheInBackground = true
            };
            var completionService = document.GetRequiredLanguageService <CompletionService>();
            var documentText      = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var completionListResult = await GetFilteredCompletionListAsync(request, documentText, document, completionOptions, completionService, cancellationToken).ConfigureAwait(false);

            if (completionListResult == null)
            {
                return(null);
            }

            var(list, isIncomplete, resultId) = completionListResult.Value;

            if (list.IsEmpty)
            {
                return(new LSP.VSInternalCompletionList
                {
                    Items = Array.Empty <LSP.CompletionItem>(),
                    SuggestionMode = list.SuggestionModeItem != null,
                    IsIncomplete = isIncomplete,
                });
            }

            var lspVSClientCapability     = context.ClientCapabilities.HasVisualStudioLspCapability() == true;
            var snippetsSupported         = context.ClientCapabilities.TextDocument?.Completion?.CompletionItem?.SnippetSupport ?? false;
            var itemDefaultsSupported     = context.ClientCapabilities.TextDocument?.Completion?.CompletionListSetting?.ItemDefaults?.Contains(EditRangeSetting) == true;
            var commitCharactersRuleCache = new Dictionary <ImmutableArray <CharacterSetModificationRule>, string[]>(CommitCharacterArrayComparer.Instance);

            // We use the first item in the completion list as our comparison point for span
            // and range for optimization when generating the TextEdits later on.
            var completionChange = await completionService.GetChangeAsync(
                document, list.Items.First(), cancellationToken : cancellationToken).ConfigureAwait(false);

            var defaultSpan  = completionChange.TextChange.Span;
            var defaultRange = ProtocolConversions.TextSpanToRange(defaultSpan, documentText);

            var supportsCompletionListData = context.ClientCapabilities.HasCompletionListDataCapability();
            var completionResolveData      = new CompletionResolveData()
            {
                ResultId = resultId,
            };
            var stringBuilder = new StringBuilder();

            using var _ = ArrayBuilder <LSP.CompletionItem> .GetInstance(out var lspCompletionItems);

            foreach (var item in list.Items)
            {
                var completionItemResolveData = supportsCompletionListData ? null : completionResolveData;
                var lspCompletionItem         = await CreateLSPCompletionItemAsync(
                    request, document, item, completionItemResolveData, lspVSClientCapability, commitCharactersRuleCache,
                    completionService, snippetsSupported, itemDefaultsSupported, stringBuilder, documentText,
                    defaultSpan, cancellationToken).ConfigureAwait(false);

                lspCompletionItems.Add(lspCompletionItem);
            }

            var completionList = new LSP.VSInternalCompletionList
            {
                Items          = lspCompletionItems.ToArray(),
                SuggestionMode = list.SuggestionModeItem != null,
                IsIncomplete   = isIncomplete,
            };

            if (supportsCompletionListData)
            {
                completionList.Data = completionResolveData;
            }

            if (context.ClientCapabilities.HasCompletionListCommitCharactersCapability())
            {
                PromoteCommonCommitCharactersOntoList(completionList);
            }

            if (itemDefaultsSupported)
            {
                completionList.ItemDefaults = new LSP.CompletionListItemDefaults
                {
                    EditRange = defaultRange,
                };
            }

            var optimizedCompletionList = new LSP.OptimizedVSCompletionList(completionList);

            return(optimizedCompletionList);

            // Local functions
            bool IsValidTriggerCharacterForDocument(Document document, char triggerCharacter)
            {
                if (document.Project.Language == LanguageNames.CSharp)
                {
                    return(_csharpTriggerCharacters.Contains(triggerCharacter));
                }
                else if (document.Project.Language == LanguageNames.VisualBasic)
                {
                    return(_vbTriggerCharacters.Contains(triggerCharacter));
                }

                // Typescript still calls into this for completion.
                // Since we don't know what their trigger characters are, just return true.
                return(true);
            }
Ejemplo n.º 15
0
        public static async Task <RequestContext?> CreateAsync(
            bool requiresLSPSolution,
            bool mutatesSolutionState,
            TextDocumentIdentifier?textDocument,
            WellKnownLspServerKinds serverKind,
            ClientCapabilities clientCapabilities,
            ImmutableArray <string> supportedLanguages,
            LspServices lspServices,
            CancellationToken queueCancellationToken,
            CancellationToken requestCancellationToken)
        {
            var lspWorkspaceManager = lspServices.GetRequiredService <LspWorkspaceManager>();
            var logger = lspServices.GetRequiredService <ILspLogger>();
            var documentChangeTracker = mutatesSolutionState ? (IDocumentChangeTracker)lspWorkspaceManager : new NonMutatingDocumentChangeTracker();

            // Retrieve the current LSP tracked text as of this request.
            // This is safe as all creation of request contexts cannot happen concurrently.
            var trackedDocuments = lspWorkspaceManager.GetTrackedLspText();

            // If the handler doesn't need an LSP solution we do two important things:
            // 1. We don't bother building the LSP solution for perf reasons
            // 2. We explicitly don't give the handler a solution or document, even if we could
            //    so they're not accidentally operating on stale solution state.
            if (!requiresLSPSolution)
            {
                return(new RequestContext(
                           solution: null, logger: logger, clientCapabilities: clientCapabilities, serverKind: serverKind, document: null,
                           documentChangeTracker: documentChangeTracker, trackedDocuments: trackedDocuments, supportedLanguages: supportedLanguages, lspServices: lspServices,
                           queueCancellationToken: queueCancellationToken));
            }

            Solution?workspaceSolution;
            Document?document = null;

            if (textDocument is not null)
            {
                // we were given a request associated with a document.  Find the corresponding roslyn document for this.
                // There are certain cases where we may be asked for a document that does not exist (for example a document is removed)
                // For example, document pull diagnostics can ask us after removal to clear diagnostics for a document.
                document = await lspWorkspaceManager.GetLspDocumentAsync(textDocument, requestCancellationToken).ConfigureAwait(false);
            }

            workspaceSolution = document?.Project.Solution ?? await lspWorkspaceManager.TryGetHostLspSolutionAsync(requestCancellationToken).ConfigureAwait(false);

            if (workspaceSolution == null)
            {
                logger.TraceError("Could not find appropriate solution for operation");
                return(null);
            }

            var context = new RequestContext(
                workspaceSolution,
                logger,
                clientCapabilities,
                serverKind,
                document,
                documentChangeTracker,
                trackedDocuments,
                supportedLanguages,
                lspServices,
                queueCancellationToken);

            return(context);
        }