/// <summary> /// Starts parsing all components of all unprotected VBProjects associated with the VBE-Instance passed to the constructor of this parser instance. /// </summary> private void ParseAll() { if (_state.Projects.Count == 0) { foreach (var project in _vbe.VBProjects.UnprotectedProjects()) { _state.AddProject(project); } } var components = new List <VBComponent>(); foreach (var project in _state.Projects) { foreach (VBComponent component in project.VBComponents) { components.Add(component); } } var toParse = new List <VBComponent>(); var unchanged = new List <VBComponent>(); foreach (var component in components) { if (_state.IsNewOrModified(component)) { toParse.Add(component); } else { unchanged.Add(component); } } SyncComReferences(_state.Projects); AddBuiltInDeclarations(_state.Projects); if (toParse.Count == 0) { State.SetStatusAndFireStateChanged(_state.Status); return; } lock (_state) // note, method is invoked from UI thread... really need the lock here? { foreach (var component in toParse) { _state.SetModuleState(component, ParserState.Pending); } foreach (var component in unchanged) { // note: seting to 'Parsed' would include them in the resolver walk. 'Ready' excludes them. _state.SetModuleState(component, ParserState.Ready); } //Debug.Assert(unchanged.All(component => _state.GetModuleState(component) == ParserState.Ready)); //Debug.Assert(toParse.All(component => _state.GetModuleState(component) == ParserState.Pending)); } // invalidation cleanup should go into ParseAsync? foreach (var key in _componentAttributes.Keys) { if (!components.Contains(key)) { _componentAttributes.Remove(key); } } var parseTasks = new Task[components.Count]; for (var i = 0; i < components.Count; i++) { parseTasks[i] = ParseAsync(components[i], CancellationToken.None); } Task.WaitAll(parseTasks); if (_state.Status != ParserState.Error) { Logger.Trace("Starting resolver task"); Resolve(_central.Token); } }