Esempio n. 1
0
        private async Task StreamingFindReferencesAsync(
            Document document, int caretPosition, IStreamingFindUsagesPresenter presenter)
        {
            try
            {
                // first, let's see if we even have a comment, otherwise there's no use in starting a search
                var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, new CancellationToken()).ConfigureAwait(false);

                var symbol = relevantSymbol?.symbol;
                if (symbol == null)
                {
                    return; // would be useful if we could notify the user why we didn't do anything
                }
                // maybe using something like an info bar?

                var findUsagesService = document.GetLanguageService <IFindUsagesService>();

                using var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferencesAsync));

                var(context, cancellationToken) = presenter.StartSearch(EditorFeaturesResources.Find_References, supportsReferences: true);

                using (Logger.LogBlock(
                           FunctionId.CommandHandler_FindAllReference,
                           KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                           cancellationToken))
                {
                    var symbolsToLookup = new List <ISymbol>();

                    foreach (var curSymbol in symbol.ContainingType.GetMembers()
                             .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name))
                    {
                        if (!document.Project.TryGetCompilation(out var compilation))
                        {
                            // TODO: should we do anything more here?
                            continue;
                        }

                        foreach (var sym in SymbolFinder.FindSimilarSymbols(curSymbol, compilation, cancellationToken))
                        {
                            // assumption here is, that FindSimilarSymbols returns symbols inside same project
                            var symbolsToAdd = await GatherSymbolsAsync(sym, document.Project.Solution, cancellationToken).ConfigureAwait(false);

                            symbolsToLookup.AddRange(symbolsToAdd);
                        }
                    }

                    foreach (var candidate in symbolsToLookup)
                    {
                        await AbstractFindUsagesService.FindSymbolReferencesAsync(context, candidate, document.Project, cancellationToken).ConfigureAwait(false);
                    }

                    // Note: we don't need to put this in a finally.  The only time we might not hit
                    // this is if cancellation or another error gets thrown.  In the former case,
                    // that means that a new search has started.  We don't care about telling the
                    // context it has completed.  In the latter case something wrong has happened
                    // and we don't want to run any more code in this particular context.
                    await context.OnCompletedAsync(cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
Esempio n. 2
0
        public async Task SearchAsync(
            bool searchCurrentDocument,
            NavigateToSearchScope scope,
            CancellationToken cancellationToken)
        {
            var isFullyLoaded = true;

            try
            {
                using var navigateToSearch = Logger.LogBlock(FunctionId.NavigateTo_Search, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken);
                using var asyncToken       = _asyncListener.BeginAsyncOperation(GetType() + ".Search");

                if (searchCurrentDocument)
                {
                    await SearchCurrentDocumentAsync(cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    // We consider ourselves fully loaded when both the project system has completed loaded us, and we've
                    // totally hydrated the oop side.  Until that happens, we'll attempt to return cached data from languages
                    // that support that.
                    isFullyLoaded = await _host.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false);
                    await SearchAllProjectsAsync(isFullyLoaded, scope, cancellationToken).ConfigureAwait(false);
                }
            }
            finally
            {
                // Ensure that we actually complete all our remaining progress items so that the progress bar completes.
                await ProgressItemsCompletedAsync(_remainingProgressItems, cancellationToken).ConfigureAwait(false);

                Debug.Assert(_remainingProgressItems == 0);

                // Pass along isFullyLoaded so that the UI can show indication to users that results may be incomplete.
                _callback.Done(isFullyLoaded);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Starts pushing events from the given projects to the workspace hosts and notifies about open documents.
        /// </summary>
        /// <remarks>This method must be called on the foreground thread.</remarks>
        internal void StartPushingToWorkspaceAndNotifyOfOpenDocuments(IEnumerable <AbstractProject> projects)
        {
            AssertIsForeground();

            // If the solution is closing we shouldn't do anything, because all of our state is
            // in the process of going away. This can happen if we receive notification that a document has
            // opened in the middle of the solution close operation.
            if (_solutionIsClosing)
            {
                return;
            }

            // We need to push these projects and any project dependencies we already know about. Therefore, compute the
            // transitive closure of the projects that haven't already been pushed, keeping them in appropriate order.
            var visited       = new HashSet <AbstractProject>();
            var inOrderToPush = new List <AbstractProject>();

            void addToInOrderToPush(AbstractProject project)
            {
                Contract.ThrowIfFalse(ContainsProject(project));

                // Bail out if any of the following is true:
                //  1. We have already started pushing changes for this project OR
                //  2. We have already visited this project in a prior recursive call
                if (_pushedProjects.Contains(project) || !visited.Add(project))
                {
                    return;
                }

                foreach (var projectReference in project.GetCurrentProjectReferences())
                {
                    addToInOrderToPush(GetProject(projectReference.ProjectId));
                }

                inOrderToPush.Add(project);
            }

            foreach (var project in projects)
            {
                addToInOrderToPush(project);
            }

            var projectInfos = inOrderToPush.Select(p => p.CreateProjectInfoForCurrentState()).ToImmutableArray();

            // We need to enable projects to start pushing changes to the workspace even before we add the solution/project to the host.
            // This is required because between the point we capture the project info for current state and the point where we start pushing to the workspace,
            // project system may send new events on the AbstractProject on a background thread, and these won't get pushed over to the workspace hosts as we didn't set the _pushingChangesToWorkspaceHost flag on the AbstractProject.
            // By invoking StartPushingToWorkspaceHosts upfront, any project state changes on the background thread will enqueue notifications to workspace hosts on foreground scheduled tasks.
            foreach (var project in inOrderToPush)
            {
                project.PushingChangesToWorkspace = true;

                Logger.Log(FunctionId.AbstractProject_PushedToWorkspace,
                           KeyValueLogMessage.Create(LogType.Trace, m =>
                {
                    m[AbstractProject.ProjectGuidPropertyName] = project.Guid;
                }));
            }

            using (WorkspaceServices.GetService <IGlobalOperationNotificationService>()?.Start("Add Project to Workspace"))
            {
                if (!_solutionAdded)
                {
                    string       solutionFilePath = null;
                    VersionStamp?version          = default;
                    // Figure out the solution version
                    if (ErrorHandler.Succeeded(_vsSolution.GetSolutionInfo(out var solutionDirectory, out var solutionFileName, out var userOptsFile)) && solutionFileName != null)
                    {
                        solutionFilePath = Path.Combine(solutionDirectory, solutionFileName);
                        if (File.Exists(solutionFilePath))
                        {
                            version = VersionStamp.Create(File.GetLastWriteTimeUtc(solutionFilePath));
                        }
                    }

                    if (version == null)
                    {
                        version = VersionStamp.Create();
                    }

                    var id = SolutionId.CreateNewId(string.IsNullOrWhiteSpace(solutionFileName) ? null : solutionFileName);

                    var solutionInfo = SolutionInfo.Create(id, version.Value, solutionFilePath, projects: projectInfos);

                    NotifyWorkspace(workspace => workspace.OnSolutionAdded(solutionInfo));

                    _solutionAdded = true;

                    var persistenceService = WorkspaceServices.GetRequiredService <IPersistentStorageLocationService>() as VisualStudioPersistentStorageLocationService;
                    persistenceService?.UpdateForVisualStudioWorkspace(_workspace);
                }
                else
                {
                    // The solution is already added, so we'll just do project added notifications from here
                    foreach (var projectInfo in projectInfos)
                    {
                        NotifyWorkspace(workspace => workspace.OnProjectAdded(projectInfo));
                    }
                }

                foreach (var project in inOrderToPush)
                {
                    _pushedProjects.Add(project);

                    foreach (var document in project.GetCurrentDocuments())
                    {
                        if (document.IsOpen)
                        {
                            NotifyWorkspace(workspace =>
                            {
                                workspace.OnDocumentOpened(
                                    document.Id,
                                    document.GetOpenTextBuffer().AsTextContainer(),
                                    isCurrentContext: LinkedFileUtilities.IsCurrentContextHierarchy(document, _runningDocumentTable));
                                (workspace as VisualStudioWorkspaceImpl)?.ConnectToSharedHierarchyEvents(document);
                            });
                        }
                    }
                }
            }
        }
Esempio n. 4
0
        private async Task ExecuteAsync(Document document, SnapshotSpan snapshotSpan, ITextView textView)
        {
            _threadingContext.ThrowIfNotOnUIThread();

            var indicatorFactory = document.Project.Solution.Services.GetRequiredService <IBackgroundWorkIndicatorFactory>();

            using var backgroundWorkContext = indicatorFactory.Create(
                      textView,
                      snapshotSpan,
                      DialogText,
                      cancelOnEdit: true,
                      cancelOnFocusLost: true);

            var cancellationToken = backgroundWorkContext.UserCancellationToken;

            // We're going to log the same thing on success or failure since this blocks the UI thread. This measurement is
            // intended to tell us how long we're blocking the user from typing with this action.
            using var blockLogger = Logger.LogBlock(FunctionId.CommandHandler_Paste_ImportsOnPaste, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken);

            var addMissingImportsService = document.GetRequiredLanguageService <IAddMissingImportsFeatureService>();

            var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false);

            var options = new AddMissingImportsOptions(
                CleanupOptions: cleanupOptions,
                HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language));

            var textSpan        = snapshotSpan.Span.ToTextSpan();
            var updatedDocument = await addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false);

            if (updatedDocument is null)
            {
                return;
            }

            // Required to switch back to the UI thread to call TryApplyChanges
            await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

            document.Project.Solution.Workspace.TryApplyChanges(updatedDocument.Project.Solution);
        }
Esempio n. 5
0
 public static KeyValueLogMessage Create(int sessionId, int editSessionId, string error)
 {
     return(KeyValueLogMessage.Create(m => CreateEditSessionErrorId(m, sessionId, editSessionId, error)));
 }
Esempio n. 6
0
 public static KeyValueLogMessage Create(int sessionId, int editSessionId, ValueTuple <ushort, ushort> rudeEdit, bool blocking)
 {
     return(KeyValueLogMessage.Create(m => CreateEditSessionRudeEdit(m, sessionId, editSessionId, rudeEdit, blocking)));
 }
Esempio n. 7
0
 public static KeyValueLogMessage Create(int sessionId, EncDebuggingSessionInfo session)
 {
     return(KeyValueLogMessage.Create(m => CreateSessionKeyValue(m, sessionId, session)));
 }
Esempio n. 8
0
 public static KeyValueLogMessage Create(int sessionId, int editSessionId, EncEditSessionInfo editSession)
 {
     return(KeyValueLogMessage.Create(m => CreateSessionEditKeyValue(m, sessionId, editSessionId, editSession)));
 }
            internal async Task SearchAsync()
            {
                try
                {
                    using var navigateToSearch = Logger.LogBlock(FunctionId.NavigateTo_Search, KeyValueLogMessage.Create(LogType.UserAction), _cancellationToken);
                    using var asyncToken       = _asyncListener.BeginAsyncOperation(GetType() + ".Search");
                    _progress.AddItems(_solution.Projects.Count());

                    var workspace = _solution.Workspace;

                    // If the workspace is tracking documents, use that to prioritize our search
                    // order.  That way we provide results for the documents the user is working
                    // on faster than the rest of the solution.
                    var docTrackingService = workspace.Services.GetService <IDocumentTrackingService>();
                    if (docTrackingService != null)
                    {
                        await SearchProjectsInPriorityOrderAsync(docTrackingService).ConfigureAwait(false);
                    }
                    else
                    {
                        await SearchAllProjectsAsync().ConfigureAwait(false);
                    }
                }
                catch (OperationCanceledException)
                {
                }
                finally
                {
                    var service = _solution.Workspace.Services.GetService <IWorkspaceStatusService>();
                    if (_callback is INavigateToCallback2 callback2 &&
                        !await service.IsFullyLoadedAsync(_cancellationToken).ConfigureAwait(false))
                    {
                        // providing this extra information will make UI to show indication to users
                        // that result might not contain full data
                        callback2.Done(IncompleteReason.SolutionLoading);
                    }
Esempio n. 10
0
        internal static void LogDebuggingSessionTelemetry(DebuggingSessionTelemetry.Data debugSessionData, Action <FunctionId, LogMessage> log, Func <int> getNextId)
        {
            const string SessionId     = nameof(SessionId);
            const string EditSessionId = nameof(EditSessionId);

            var debugSessionId = getNextId();

            log(FunctionId.Debugging_EncSession, KeyValueLogMessage.Create(map =>
            {
                map[SessionId]           = debugSessionId;
                map["SessionCount"]      = debugSessionData.EditSessionData.Length;
                map["EmptySessionCount"] = debugSessionData.EmptyEditSessionCount;
            }));

            foreach (var editSessionData in debugSessionData.EditSessionData)
            {
                var editSessionId = getNextId();

                log(FunctionId.Debugging_EncSession_EditSession, KeyValueLogMessage.Create(map =>
                {
                    map[SessionId]     = debugSessionId;
                    map[EditSessionId] = editSessionId;

                    map["HadCompilationErrors"]         = editSessionData.HadCompilationErrors;
                    map["HadRudeEdits"]                 = editSessionData.HadRudeEdits;
                    map["HadValidChanges"]              = editSessionData.HadValidChanges;
                    map["HadValidInsignificantChanges"] = editSessionData.HadValidInsignificantChanges;

                    map["RudeEditsCount"]        = editSessionData.RudeEdits.Length;
                    map["EmitDeltaErrorIdCount"] = editSessionData.EmitErrorIds.Length;
                }));

                foreach (var errorId in editSessionData.EmitErrorIds)
                {
                    log(FunctionId.Debugging_EncSession_EditSession_EmitDeltaErrorId, KeyValueLogMessage.Create(map =>
                    {
                        map[SessionId]     = debugSessionId;
                        map[EditSessionId] = editSessionId;
                        map["ErrorId"]     = errorId;
                    }));
                }

                foreach (var(editKind, syntaxKind) in editSessionData.RudeEdits)
                {
                    log(FunctionId.Debugging_EncSession_EditSession_RudeEdit, KeyValueLogMessage.Create(map =>
                    {
                        map[SessionId]     = debugSessionId;
                        map[EditSessionId] = editSessionId;

                        map["RudeEditKind"]       = editKind;
                        map["RudeEditSyntaxKind"] = syntaxKind;
                        map["RudeEditBlocking"]   = editSessionData.HadRudeEdits;
                    }));
                }
            }
        }
 private static void LogWorkspaceAnalyzerCount(int analyzerCount)
 {
     Logger.Log(FunctionId.DiagnosticAnalyzerService_Analyzers, KeyValueLogMessage.Create(m => m["AnalyzerCount"] = analyzerCount));
 }
        private async Task FindImplementingMembersAsync(
            Document document, int caretPosition,
            IStreamingFindUsagesPresenter presenter)
        {
            try
            {
                using (var token = _asyncListener.BeginAsyncOperation(nameof(FindImplementingMembersAsync)))
                {
                    // Let the presented know we're starting a search.
                    var context = presenter.StartSearch(
                        EditorFeaturesResources.Navigating, supportsReferences: true);

                    using (Logger.LogBlock(
                               FunctionId.CommandHandler_FindAllReference,
                               KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                               context.CancellationToken))
                    {
                        try
                        {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, context.CancellationToken);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                            var interfaceSymbol = relevantSymbol?.symbol as INamedTypeSymbol;

                            if (interfaceSymbol == null || interfaceSymbol.TypeKind != TypeKind.Interface)
                            {
                                //looks like it's not a relevant symbol
                                return;
                            }

                            // we now need to find the class that implements this particular interface, at the
                            // caret position, or somewhere around it
                            SyntaxNode nodeRoot;
                            if (!document.TryGetSyntaxRoot(out nodeRoot))
                            {
                                return;
                            }

#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var syntaxTree = await document.GetSyntaxTreeAsync();

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                            var documentToken = nodeRoot.FindToken(caretPosition);

                            if (!documentToken.Span.IntersectsWith(caretPosition))
                            {
                                return; // looks like it's not relevant
                            }
                            // the parents should bring us to the class definition
                            var parentTypeNode = documentToken.Parent?.Parent?.Parent?.Parent;
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            var compilation = await document.Project.GetCompilationAsync();

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                            // let's finally get our implementing type
                            var namedTypeSymbol = compilation.GetSemanticModel(syntaxTree).GetDeclaredSymbol(parentTypeNode) as INamedTypeSymbol;
                            // unless something went wrong, and we got an empty symbol,
                            if (namedTypeSymbol == null)
                            {
                                return;
                            }

                            // we can search for implementations of the interface, within this type
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                            await InspectInterfaceAsync(context, interfaceSymbol, namedTypeSymbol, document.Project);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task

                            // now, we iterate on interfaces of our interfaces
                            foreach (var iFace in interfaceSymbol.AllInterfaces)
                            {
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
                                await InspectInterfaceAsync(context, iFace, namedTypeSymbol, document.Project);

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
                            }
                        }
                        finally
                        {
                            await context.OnCompletedAsync().ConfigureAwait(false);
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
Esempio n. 13
0
 public static void LogDiagnosticsStats(ImmutableDictionary <Project, ImmutableArray <Diagnostic> > projectsAndDiagnosticsToFixMap)
 {
     Logger.Log(FunctionId.CodeFixes_FixAllOccurrencesComputation_Diagnostics, KeyValueLogMessage.Create(m =>
     {
         m[s_projectsWithDiagnosticsToFix] = projectsAndDiagnosticsToFixMap.Count;
         m[s_totalDiagnosticsToFix]        = projectsAndDiagnosticsToFixMap.Values.Sum(v => v.Length);
     }));
 }
Esempio n. 14
0
        private async Task FindExtensionMethodsAsync(
            Document document, int caretPosition, IStreamingFindUsagesPresenter presenter)
        {
            var solution = document.Project.Solution;

            try
            {
                using var token = _asyncListener.BeginAsyncOperation(nameof(FindExtensionMethodsAsync));

                var(context, cancellationToken) = presenter.StartSearch(EditorFeaturesResources.Navigating, supportsReferences: true);

                try
                {
                    using (Logger.LogBlock(
                               FunctionId.CommandHandler_FindAllReference,
                               KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"),
                               cancellationToken))
                    {
                        var candidateSymbolProjectPair = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, cancellationToken).ConfigureAwait(false);

                        var symbol = candidateSymbolProjectPair?.symbol as INamedTypeSymbol;

                        // if we didn't get the right symbol, just abort
                        if (symbol == null)
                        {
                            return;
                        }

                        if (!document.Project.TryGetCompilation(out var compilation))
                        {
                            return;
                        }

                        foreach (var type in compilation.Assembly.GlobalNamespace.GetAllTypes(cancellationToken))
                        {
                            if (!type.MightContainExtensionMethods)
                            {
                                continue;
                            }

                            foreach (var extMethod in type.GetMembers().OfType <IMethodSymbol>().Where(method => method.IsExtensionMethod))
                            {
                                if (cancellationToken.IsCancellationRequested)
                                {
                                    break;
                                }

                                var reducedMethod = extMethod.ReduceExtensionMethod(symbol);
                                if (reducedMethod != null)
                                {
                                    var loc = extMethod.Locations.First();

                                    var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(reducedMethod, solution, cancellationToken).ConfigureAwait(false);

                                    // And if our definition actually is from source, then let's re-figure out what project it came from
                                    if (sourceDefinition != null)
                                    {
                                        var originatingProject = solution.GetProject(sourceDefinition.ContainingAssembly, cancellationToken);

                                        var definitionItem = reducedMethod.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

                                        await context.OnDefinitionFoundAsync(definitionItem, cancellationToken).ConfigureAwait(false);
                                    }
                                }
                            }
                        }
                    }
                }
                finally
                {
                    await context.OnCompletedAsync(cancellationToken).ConfigureAwait(false);
                }
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e) when(FatalError.ReportAndCatch(e))
            {
            }
        }
        internal static Solution PreviewChanges(
            Solution currentSolution,
            Solution newSolution,
            string fixAllPreviewChangesTitle,
            string fixAllTopLevelHeader,
            FixAllKind fixAllKind,
            string languageOpt,
            Workspace workspace,
            int?correlationId = null,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var functionId = fixAllKind switch
            {
                FixAllKind.CodeFix => FunctionId.CodeFixes_FixAllOccurrencesPreviewChanges,
                FixAllKind.Refactoring => FunctionId.Refactoring_FixAllOccurrencesPreviewChanges,
                _ => throw ExceptionUtilities.UnexpectedValue(fixAllKind)
            };

            using (Logger.LogBlock(
                       functionId,
                       KeyValueLogMessage.Create(LogType.UserAction, m =>
            {
                // only set when correlation id is given
                // we might not have this info for suppression
                if (correlationId.HasValue)
                {
                    m[FixAllLogger.CorrelationId] = correlationId;
                }
            }),
                       cancellationToken))
            {
                var glyph = languageOpt == null
                    ? Glyph.Assembly
                    : languageOpt == LanguageNames.CSharp
                        ? Glyph.CSharpProject
                        : Glyph.BasicProject;
#if COCOA
                var previewService = workspace.Services.GetService <IPreviewDialogService>();

                // Until IPreviewDialogService is implemented, just execute all changes without user ability to pick and choose
                if (previewService == null)
                {
                    return(newSolution);
                }
#else
                var previewService = workspace.Services.GetRequiredService <IPreviewDialogService>();
#endif

                var changedSolution = previewService.PreviewChanges(
                    string.Format(EditorFeaturesResources.Preview_Changes_0, fixAllPreviewChangesTitle),
                    "vs.codefix.fixall",
                    fixAllTopLevelHeader,
                    fixAllPreviewChangesTitle,
                    glyph,
                    newSolution,
                    currentSolution);

                if (changedSolution == null)
                {
                    // User clicked cancel.
                    FixAllLogger.LogPreviewChangesResult(fixAllKind, correlationId, applied: false);
                    return(null);
                }

                FixAllLogger.LogPreviewChangesResult(fixAllKind, correlationId, applied: true, allChangesApplied: changedSolution == newSolution);
                return(changedSolution);
            }
        }