示例#1
0
        private void ExecuteCommonParseActivities(IReadOnlyCollection <QualifiedModuleName> toParse, IReadOnlyCollection <QualifiedModuleName> toReresolveReferencesInput, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            var toReresolveReferences = new HashSet <QualifiedModuleName>();

            toReresolveReferences.UnionWith(toReresolveReferencesInput);
            token.ThrowIfCancellationRequested();

            _parserStateManager.SetModuleStates(toParse, ParserState.Pending, token);
            token.ThrowIfCancellationRequested();

            _parserStateManager.SetStatusAndFireStateChanged(this, ParserState.LoadingReference, token);
            token.ThrowIfCancellationRequested();

            _parsingStageService.SyncComReferences(State.Projects, token);
            if (_parsingStageService.LastSyncOfCOMReferencesLoadedReferences || _parsingStageService.COMReferencesUnloadedUnloadedInLastSync.Any())
            {
                var unloadedReferences = _parsingStageService.COMReferencesUnloadedUnloadedInLastSync;
                var additionalModulesToBeReresolved = OtherModulesReferencingAnyNotToBeParsed(unloadedReferences.ToHashSet().AsReadOnly(), toParse);
                toReresolveReferences.UnionWith(additionalModulesToBeReresolved);
                _parserStateManager.SetModuleStates(additionalModulesToBeReresolved, ParserState.ResolvingReferences, token);
                ClearModuleToModuleReferences(unloadedReferences);
                RefreshDeclarationFinder();
            }
            token.ThrowIfCancellationRequested();

            _parsingStageService.LoadBuitInDeclarations();
            if (_parsingStageService.LastLoadOfBuiltInDeclarationsLoadedDeclarations)
            {
                RefreshDeclarationFinder();
            }
            token.ThrowIfCancellationRequested();

            IReadOnlyCollection <QualifiedModuleName> toResolveReferences;

            if (!toParse.Any())
            {
                toResolveReferences = toReresolveReferences.AsReadOnly();
            }
            else
            {
                toResolveReferences = ModulesForWhichToResolveReferences(toParse, toReresolveReferences);
                token.ThrowIfCancellationRequested();

                PerformPreParseCleanup(toResolveReferences, token);
                token.ThrowIfCancellationRequested();

                _parserStateManager.SetModuleStates(toParse, ParserState.Parsing, token);
                token.ThrowIfCancellationRequested();

                _parsingStageService.ParseModules(toParse, token);

                if (token.IsCancellationRequested || State.Status >= ParserState.Error)
                {
                    throw new OperationCanceledException(token);
                }

                _parserStateManager.EvaluateOverallParserState(token);

                if (token.IsCancellationRequested || State.Status >= ParserState.Error)
                {
                    throw new OperationCanceledException(token);
                }

                _parserStateManager.SetModuleStates(toParse, ParserState.ResolvingDeclarations, token);
                token.ThrowIfCancellationRequested();

                _parsingStageService.ResolveDeclarations(toParse, token);
            }

            if (token.IsCancellationRequested || State.Status >= ParserState.Error)
            {
                throw new OperationCanceledException(token);
            }

            //We need to refresh the DeclarationFinder before the handlers for ResolvedDeclarations run no matter
            //whether we parsed or resolved something because modules not referenced by any remeining module might
            //have been removed. E.g. the CodeExplorer needs this update.
            RefreshDeclarationFinder();
            token.ThrowIfCancellationRequested();

            //Explicitly setting the overall state here guarantees that the handlers attached
            //to the state change to ResolvedDeclarations always run, provided there is no error.
            State.SetStatusAndFireStateChanged(this, ParserState.ResolvedDeclarations);

            if (token.IsCancellationRequested || State.Status >= ParserState.Error)
            {
                throw new OperationCanceledException(token);
            }

            _parserStateManager.SetModuleStates(toResolveReferences, ParserState.ResolvingReferences, token);
            token.ThrowIfCancellationRequested();

            _parsingStageService.ResolveReferences(toResolveReferences, token);

            if (token.IsCancellationRequested || State.Status >= ParserState.Error)
            {
                throw new OperationCanceledException(token);
            }

            RefreshDeclarationFinder();
            token.ThrowIfCancellationRequested();

            //At this point all modules should either be in the Ready state or in an error state.
            //This is the point where the change of the overall state to Ready is triggered on the success path.
            _parserStateManager.EvaluateOverallParserState(token);
            token.ThrowIfCancellationRequested();
        }
示例#2
0
        public void SuspendRequested(object sender, RubberduckStatusSuspendParserEventArgs e)
        {
            if (ParsingSuspendLock.IsReadLockHeld)
            {
                e.Result = SuspensionResult.UnexpectedError;
                const string errorMessage =
                    "A suspension action was attempted while a read lock was held. This indicates a bug in the code logic as suspension should not be requested from same thread that has a read lock.";
                Logger.Error(errorMessage);
#if DEBUG
                Debug.Assert(false, errorMessage);
#endif
                return;
            }

            object parseRequestor = null;
            try
            {
                if (!ParsingSuspendLock.TryEnterWriteLock(e.MillisecondsTimeout))
                {
                    e.Result = SuspensionResult.TimedOut;
                    return;
                }

                lock (SuspendStackSyncObject)
                {
                    _isSuspended = true;
                }

                var originalStatus = State.Status;
                if (!e.AllowedRunStates.Contains(originalStatus))
                {
                    e.Result = SuspensionResult.IncompatibleState;
                    return;
                }
                _parserStateManager.SetStatusAndFireStateChanged(e.Requestor, ParserState.Busy,
                                                                 CancellationToken.None);
                e.BusyAction.Invoke();
            }
            catch
            {
                e.Result = SuspensionResult.UnexpectedError;
                throw;
            }
            finally
            {
                lock (SuspendStackSyncObject)
                {
                    _isSuspended = false;
                    if (_requestorStack.TryPop(out var lastRequestor))
                    {
                        _requestorStack.Clear();
                        parseRequestor = lastRequestor;
                    }

                    // Though there were no reparse requests, we need to reset the state before we release the
                    // write lock to avoid introducing discrepancy in the parser state due to readers being
                    // blocked. Any reparse requests must be done outside the write lock; see further below.
                    if (parseRequestor == null)
                    {
                        // We cannot make any assumptions about the original state, nor do we know
                        // anything about resuming the previous state, so we must delegate the state
                        // evaluation to the state manager.
                        _parserStateManager.EvaluateOverallParserState(CancellationToken.None);
                    }
                }

                if (ParsingSuspendLock.IsWriteLockHeld)
                {
                    ParsingSuspendLock.ExitWriteLock();
                }

                if (e.Result == SuspensionResult.Pending)
                {
                    e.Result = SuspensionResult.Completed;
                }
            }

            // Any reparse requests must be done outside the write lock to avoid deadlocks
            if (parseRequestor != null)
            {
                BeginParse(parseRequestor);
            }
        }