/// <summary> /// Handles the <see cref="IActiveConfiguredProjectSubscriptionService"/> callback on the active configured project's /// design-time build change notification service. /// </summary> private async Task ProjectBuildRuleBlock_ChangedAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e) { await ThreadingService.SwitchToUIThread(); using (ProjectAsynchronousTasksService.LoadedProject()) { foreach (var resolvedReferenceChange in e.Value.ProjectChanges.Values) { if (!WatchedDesignTimeBuildRules.Contains(resolvedReferenceChange.After.RuleName)) { // This is an evaluation rule. continue; } foreach (string resolvedReferencePath in resolvedReferenceChange.Difference.AddedItems) { // If this is a resolved project reference, we need to treat it specially. string originalItemSpec = resolvedReferenceChange.After.Items[resolvedReferencePath]["OriginalItemSpec"]; if (!string.IsNullOrEmpty(originalItemSpec)) { if (e.Value.CurrentState[ProjectReference.SchemaName].Items.ContainsKey(originalItemSpec)) { string originalFullPath = UnconfiguredProject.MakeRooted(originalItemSpec); ProjectReferenceState state; if (!_projectReferenceFullPaths.TryGetValue(originalFullPath, out state)) { _projectReferenceFullPaths = _projectReferenceFullPaths.Add(originalFullPath, state = new ProjectReferenceState()); } state.ResolvedPath = resolvedReferencePath; // Be careful to not add assembly references that overlap with project references. if (state.AsProjectReference) { continue; } } } Marshal.ThrowExceptionForHR(_intellisenseEngine.AddAssemblyReference(resolvedReferencePath)); } foreach (string resolvedReferencePath in resolvedReferenceChange.Difference.RemovedItems) { Marshal.ThrowExceptionForHR(_intellisenseEngine.RemoveAssemblyReference(resolvedReferencePath)); } Marshal.ThrowExceptionForHR(_intellisenseEngine.StartIntellisenseEngine()); } } }
/// <summary> /// Handles the <see cref="IActiveConfiguredProjectSubscriptionService"/> callback event on the active configured project's /// change notification service. /// </summary> private async System.Threading.Tasks.Task ProjectRuleBlock_ChangedAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e) { await ThreadingService.SwitchToUIThread(); await ProjectAsynchronousTasksService.LoadedProjectAsync(async delegate { var sourceFiles = e.Value.ProjectChanges[CSharp.SchemaName]; var projectReferences = e.Value.ProjectChanges[ProjectReference.SchemaName]; #pragma warning disable CA2007 // Do not directly await a Task (see https://github.com/dotnet/roslyn/issues/6770) var treeUpdate = await ProjectTreeService.PublishLatestTreeAsync(blockDuringLoadingTree: true); #pragma warning restore CA2007 // Do not directly await a Task var tree = treeUpdate.Tree; foreach (var sourceUnit in sourceFiles.Difference.AddedItems.Select(item => SourceFileToLanguageServiceUnit(item, tree)).Where(u => u != null)) { Marshal.ThrowExceptionForHR(_intellisenseEngine.AddFile(sourceUnit.Item1, sourceUnit.Item2)); } foreach (var sourceUnit in sourceFiles.Difference.RemovedItems.Select(item => SourceFileToLanguageServiceUnit(item, tree)).Where(u => u != null)) { Marshal.ThrowExceptionForHR(_intellisenseEngine.RemoveFile(sourceUnit.Item1, sourceUnit.Item2)); } foreach (KeyValuePair <string, string> sourceFileNames in sourceFiles.Difference.RenamedItems) { var newSourceUnit = SourceFileToLanguageServiceUnit(sourceFileNames.Value, tree); if (newSourceUnit != null) { string beforeAbsolutePath = UnconfiguredProject.MakeRooted(sourceFileNames.Key); Marshal.ThrowExceptionForHR(_intellisenseEngine.RenameFile(beforeAbsolutePath, newSourceUnit.Item1, newSourceUnit.Item2)); } } foreach (string projectReferencePath in projectReferences.Difference.AddedItems) { string projectReferenceFullPath = UnconfiguredProject.MakeRooted(projectReferencePath); ProjectReferenceState state; if (!_projectReferenceFullPaths.TryGetValue(projectReferenceFullPath, out state)) { _projectReferenceFullPaths = _projectReferenceFullPaths.Add(projectReferenceFullPath, state = new ProjectReferenceState()); } IVsIntellisenseProject intellisenseProject; if (LanguageServiceRegister.TryGetIntellisenseProject(projectReferenceFullPath, out intellisenseProject)) { if (state.ResolvedPath != null && !state.AsProjectReference) { Marshal.ThrowExceptionForHR(_intellisenseEngine.RemoveAssemblyReference(state.ResolvedPath)); } state.AsProjectReference = true; Marshal.ThrowExceptionForHR(_intellisenseEngine.AddP2PReference(intellisenseProject)); } } foreach (string projectReferencePath in projectReferences.Difference.RemovedItems) { string projectReferenceFullPath = UnconfiguredProject.MakeRooted(projectReferencePath); _projectReferenceFullPaths = _projectReferenceFullPaths.Remove(projectReferenceFullPath); IVsIntellisenseProject intellisenseProject; if (LanguageServiceRegister.TryGetIntellisenseProject(projectReferencePath, out intellisenseProject)) { Marshal.ThrowExceptionForHR(_intellisenseEngine.RemoveP2PReference(_intellisenseEngine)); } ProjectReferenceState state; if (_projectReferenceFullPaths.TryGetValue(projectReferenceFullPath, out state)) { state.AsProjectReference = false; } } Marshal.ThrowExceptionForHR(_intellisenseEngine.StartIntellisenseEngine()); }); }
/// <summary> /// Invoked when the UnconfiguredProject is first loaded to initialize language services. /// </summary> protected async Task InitializeAsync() { ProjectAsynchronousTasksService.UnloadCancellationToken.ThrowIfCancellationRequested(); // Don't start until the project has been loaded as far as the IDE is concerned. #pragma warning disable CA2007 // Do not directly await a Task (see https://github.com/dotnet/roslyn/issues/6770) await ProjectAsyncLoadDashboard.ProjectLoadedInHost; #pragma warning restore CA2007 // Do not directly await a Task // Defer this work until VS has idle time. Otherwise we'll block the UI thread to load the MSBuild project evaluation // during synchronous project load time. await ThreadHelper.JoinableTaskFactory.RunAsync( VsTaskRunContext.UIThreadBackgroundPriority, async delegate { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); await Task.Yield(); using (ProjectAsynchronousTasksService.LoadedProject()) { // hack to ensure webproj package is properly sited, by forcing it to load with a QueryService call for // one of the services it implements. var tmpObj = Package.GetGlobalService(typeof(SWebApplicationCtxSvc)) as IWebApplicationCtxSvc; Report.IfNotPresent(tmpObj); if (tmpObj == null) { return; } // Create the Intellisense engine for C# var registry = ServiceProvider.GetService(typeof(SLocalRegistry)) as ILocalRegistry3; Assumes.Present(registry); IntPtr pIntellisenseEngine = IntPtr.Zero; try { Marshal.ThrowExceptionForHR(registry.CreateInstance( IntelliSenseProviderGuid, null, typeof(IVsIntellisenseProject).GUID, (uint)CLSCTX.CLSCTX_INPROC_SERVER, out pIntellisenseEngine)); _intellisenseEngine = Marshal.GetObjectForIUnknown(pIntellisenseEngine) as IVsIntellisenseProject; } finally { if (pIntellisenseEngine != IntPtr.Zero) { Marshal.Release(pIntellisenseEngine); } } Marshal.ThrowExceptionForHR(_intellisenseEngine.Init(this)); #pragma warning disable CA2007 // Do not directly await a Task (see https://github.com/dotnet/roslyn/issues/6770) await LanguageServiceRegister.RegisterProjectAsync(this); #pragma warning restore CA2007 // Do not directly await a Task } }); // The rest of this can execute on a worker thread. await TaskScheduler.Default; using (ProjectAsynchronousTasksService.LoadedProject()) { var designTimeBuildBlock = new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >( ProjectBuildRuleBlock_ChangedAsync); _designTimeBuildSubscriptionLink = ActiveConfiguredProjectSubscriptionService.JointRuleSource.SourceBlock.LinkTo( designTimeBuildBlock, ruleNames: WatchedEvaluationRules.Union(WatchedDesignTimeBuildRules)); var evaluationBlock = new ActionBlock <IProjectVersionedValue <IProjectSubscriptionUpdate> >( ProjectRuleBlock_ChangedAsync); _evaluationSubscriptionLink = ActiveConfiguredProjectSubscriptionService.JointRuleSource.SourceBlock.LinkTo( evaluationBlock, ruleNames: WatchedEvaluationRules); } }