예제 #1
0
        public override async Task <string> OnGetEvaluatedPropertyValueAsync(string evaluatedPropertyValue, IProjectProperties defaultProperties)
        {
            ActiveConfiguredObjects <ConfiguredProject>?configuredProjects = await _projectProvider.GetActiveConfiguredProjectsAsync();

            if (configuredProjects == null)
            {
                return("");
            }

            var builder = PooledArray <string> .GetInstance();

            foreach (ConfiguredProject configuredProject in configuredProjects.Objects)
            {
                ProjectProperties    projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>();
                ConfigurationGeneral configuration     = await projectProperties.GetConfigurationGeneralPropertiesAsync();

                string?currentTargetFrameworkMoniker = (string?)await configuration.TargetFrameworkMoniker.GetValueAsync();

                Assumes.NotNull(currentTargetFrameworkMoniker);
                builder.Add(currentTargetFrameworkMoniker !);
            }

            return(string.Join(";", builder.ToArrayAndFree()));
        }
예제 #2
0
        public override async Task <string?> OnSetPropertyValueAsync(
            string propertyName,
            string unevaluatedPropertyValue,
            IProjectProperties defaultProperties,
            IReadOnlyDictionary <string, string>?dimensionalConditions = null)
        {
            ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync();

            string?currentTargetFramework = (string?)await configuration.TargetFramework.GetValueAsync();

            string?currentTargetFrameworks = (string?)await configuration.TargetFrameworks.GetValueAsync();

            if (!string.IsNullOrEmpty(currentTargetFrameworks))
            {
                throw new InvalidOperationException(VSResources.MultiTFEditNotSupported);
            }
            else if (!string.IsNullOrEmpty(currentTargetFramework))
            {
                await defaultProperties.SetPropertyValueAsync(ConfigurationGeneral.TargetFrameworkProperty, unevaluatedPropertyValue);
            }
            else
            {
                // CPS implements IVsHierarchy.SetProperty for the TFM property to call through the multi-targeting service and change the TFM.
                // This causes the project to be reloaded after changing the values.
                // Since the property providers are called under a write-lock, trying to reload the project on the same context fails saying it can't load the project
                // if a lock is held. We are not going to write to the file under this lock (we return null from this method) and so we fork execution here to schedule
                // a lambda on the UI thread and we don't pass the lock information from this context to the new one.
                _unconfiguredProjectVsServices.ThreadingService.RunAndForget(() =>
                {
                    _unconfiguredProjectVsServices.VsHierarchy.SetProperty(HierarchyId.Root, (int)VsHierarchyPropID.TargetFrameworkMoniker, unevaluatedPropertyValue);
                    return(System.Threading.Tasks.Task.CompletedTask);
                }, options: ForkOptions.HideLocks | ForkOptions.StartOnMainThread,
                                                                             unconfiguredProject: _unconfiguredProjectVsServices.Project);
            }
            return(null);
        }
        public async Task <AggregateCrossTargetProjectContext> CreateProjectContextAsync()
        {
            // Get the set of active configured projects ignoring target framework.
#pragma warning disable CS0618 // Type or member is obsolete
            ImmutableDictionary <string, ConfiguredProject> configuredProjectsMap = await _activeConfiguredProjectsProvider.GetActiveConfiguredProjectsMapAsync();

#pragma warning restore CS0618 // Type or member is obsolete
            ProjectConfiguration activeProjectConfiguration             = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
            ImmutableArray <ITargetFramework> .Builder targetFrameworks = ImmutableArray.CreateBuilder <ITargetFramework>(initialCapacity: configuredProjectsMap.Count);
            ITargetFramework activeTargetFramework = TargetFramework.Empty;

            foreach ((string tfm, ConfiguredProject configuredProject) in configuredProjectsMap)
            {
                ProjectProperties    projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>();
                ConfigurationGeneral configurationGeneralProperties = await projectProperties.GetConfigurationGeneralPropertiesAsync();

                ITargetFramework targetFramework = await GetTargetFrameworkAsync(tfm, configurationGeneralProperties);

                targetFrameworks.Add(targetFramework);

                if (activeTargetFramework.Equals(TargetFramework.Empty) &&
                    configuredProject.ProjectConfiguration.Equals(activeProjectConfiguration))
                {
                    activeTargetFramework = targetFramework;
                }
            }

            bool isCrossTargeting = !(configuredProjectsMap.Count == 1 && string.IsNullOrEmpty(configuredProjectsMap.First().Key));

            return(new AggregateCrossTargetProjectContext(
                       isCrossTargeting,
                       targetFrameworks.MoveToImmutable(),
                       configuredProjectsMap,
                       activeTargetFramework,
                       _targetFrameworkProvider));
        }
        private async Task <string?> GetTemplateLanguageAsync()
        {
            ConfigurationGeneral general = await _properties.GetConfigurationGeneralPropertiesAsync();

            return((string?)await general.TemplateLanguage.GetValueAsync());
        }
        /// <summary>
        /// Ensures that <see cref="_currentAggregateProjectContext"/> is updated for the latest target frameworks from the project properties
        /// and returns this value.
        /// </summary>
        private async Task <AggregateWorkspaceProjectContext> UpdateProjectContextAsync()
        {
            // Ensure that only single thread is attempting to create a project context.
            AggregateWorkspaceProjectContext previousContextToDispose = null;

            return(await ExecuteWithinLockAsync(async() =>
            {
                await _commonServices.ThreadingService.SwitchToUIThread();

                string newTargetFramework = null;
                ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(false);

                // Check if we have already computed the project context.
                if (_currentAggregateProjectContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.

                    if (!_currentAggregateProjectContext.IsCrossTargeting)
                    {
                        newTargetFramework = (string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false);
                        if (StringComparers.PropertyValues.Equals(_currentTargetFramework, newTargetFramework))
                        {
                            return _currentAggregateProjectContext;
                        }

                        // Dispose the old workspace project context for the previous target framework.
                        await DisposeAggregateProjectContextAsync(_currentAggregateProjectContext).ConfigureAwait(false);
                    }
                    else
                    {
                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync().ConfigureAwait(false);
                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            _currentAggregateProjectContext.HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations))
                        {
                            return _currentAggregateProjectContext;
                        }

                        previousContextToDispose = _currentAggregateProjectContext;
                    }
                }
                else
                {
                    newTargetFramework = (string)await projectProperties.TargetFramework.GetValueAsync().ConfigureAwait(false);
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();
                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync().ConfigureAwait(false);

                // Create new project context.
                _currentAggregateProjectContext = await _contextProvider.Value.CreateProjectContextAsync().ConfigureAwait(false);
                _currentTargetFramework = newTargetFramework;

                // Dispose the old project context, if one exists.
                if (previousContextToDispose != null)
                {
                    await DisposeAggregateProjectContextAsync(previousContextToDispose).ConfigureAwait(false);
                }

                return _currentAggregateProjectContext;
            }).ConfigureAwait(false));
        }
예제 #6
0
        private async Task <Guid> GetLanguageServiceId()
        {
            ConfigurationGeneral properties = await _projectVsServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

            return(await properties.LanguageServiceId.GetValueAsGuidAsync());
        }
예제 #7
0
        /// <summary>
        /// Determines whether the current project context object is out of date based on the project's target frameworks.
        /// If so, a new one is created and subscriptions are updated accordingly.
        /// </summary>
        private async Task UpdateProjectContextAndSubscriptionsAsync()
        {
            // Ensure that only single thread is attempting to create a project context.
            AggregateCrossTargetProjectContext newProjectContext = await ExecuteWithinLockAsync(TryUpdateCurrentAggregateProjectContextAsync);

            if (newProjectContext != null)
            {
                // Dispose existing subscriptions.
                DisposeAndClearSubscriptions();

                // Add subscriptions for the configured projects in the new project context.
                await AddSubscriptionsAsync(newProjectContext);
            }

            return;

            async Task <AggregateCrossTargetProjectContext> TryUpdateCurrentAggregateProjectContextAsync()
            {
                AggregateCrossTargetProjectContext previousContext = _currentAggregateProjectContext;

                // Check if we have already computed the project context.
                if (previousContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.
                    ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

                    if (!previousContext.IsCrossTargeting)
                    {
                        string newTargetFrameworkName = (string)await projectProperties.TargetFramework.GetValueAsync();

                        ITargetFramework newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName);
                        if (previousContext.ActiveTargetFramework.Equals(newTargetFramework))
                        {
                            // No change
                            return(null);
                        }
                    }
                    else
                    {
                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync();

                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            HasMatchingTargetFrameworks(previousContext, activeProjectConfiguration, knownProjectConfigurations))
                        {
                            // No change
                            return(null);
                        }
                    }
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();

                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync();

                // Create new project context.
                AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync();

                _currentAggregateProjectContext = newContext;

                OnAggregateContextChanged(previousContext, newContext);

                return(newContext);
            }

            bool HasMatchingTargetFrameworks(
                AggregateCrossTargetProjectContext previousContext,
                ProjectConfiguration activeProjectConfiguration,
                IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations)
            {
                Assumes.True(activeProjectConfiguration.IsCrossTargeting());

                ITargetFramework activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]);

                if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework))
                {
                    // Active target framework is different.
                    return(false);
                }

                var targetFrameworkMonikers = knownProjectConfigurations
                                              .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty])
                                              .Distinct()
                                              .ToList();

                if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length)
                {
                    // Different number of target frameworks.
                    return(false);
                }

                foreach (string targetFrameworkMoniker in targetFrameworkMonikers)
                {
                    ITargetFramework targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker);

                    if (!previousContext.TargetFrameworks.Contains(targetFramework))
                    {
                        // Differing TargetFramework
                        return(false);
                    }
                }

                return(true);
            }

            void OnAggregateContextChanged(
                AggregateCrossTargetProjectContext oldContext,
                AggregateCrossTargetProjectContext newContext)
            {
                if (oldContext == null)
                {
                    // all new rules will be sent to new context, we don't need to clean up anything
                    return;
                }

                var targetsToClean = new HashSet <ITargetFramework>();

                ImmutableArray <ITargetFramework> oldTargets = oldContext.TargetFrameworks;

                if (newContext == null)
                {
                    targetsToClean.AddRange(oldTargets);
                }
                else
                {
                    ImmutableArray <ITargetFramework> newTargets = newContext.TargetFrameworks;

                    targetsToClean.AddRange(oldTargets.Except(newTargets));
                }

                if (targetsToClean.Count != 0)
                {
                    TryUpdateSnapshot(snapshot => snapshot.RemoveTargets(targetsToClean));
                }
            }
        }
예제 #8
0
        private async Task <string> GetTargetPathAsync()
        {
            ConfigurationGeneral properties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

            return((string)await properties.TargetPath.GetValueAsync());
        }
        private async Task <ComplexTargetFramework> GetStoredPropertiesAsync()
        {
            ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync();

            return(await GetStoredComplexTargetFrameworkAsync(configuration));
        }
        private static async Task <ComplexTargetFramework> GetStoredComplexTargetFrameworkAsync(ConfigurationGeneral configuration)
        {
            ComplexTargetFramework storedValues = new ComplexTargetFramework
            {
                TargetFrameworkMoniker   = (string?)await configuration.TargetFrameworkMoniker.GetValueAsync(),
                TargetPlatformIdentifier = (string?)await configuration.TargetPlatformIdentifier.GetValueAsync(),
                TargetPlatformVersion    = (string?)await configuration.TargetPlatformVersion.GetValueAsync(),
                TargetFramework          = (string?)await configuration.TargetFramework.GetValueAsync()
            };

            return(storedValues);
        }
            public async Task <AggregateCrossTargetProjectContext?> TryUpdateCurrentAggregateProjectContextAsync()
            {
                AggregateCrossTargetProjectContext?previousContext = Current;

                // Check if we have already computed the project context.
                if (previousContext != null)
                {
                    // For non-cross targeting projects, we can use the current project context if the TargetFramework hasn't changed.
                    // For cross-targeting projects, we need to verify that the current project context matches latest frameworks targeted by the project.
                    // If not, we create a new one and dispose the current one.
                    ConfigurationGeneral projectProperties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

                    if (!previousContext.IsCrossTargeting)
                    {
                        string?newTargetFrameworkName = (string?)await projectProperties.TargetFrameworkMoniker.GetValueAsync();

                        if (string.IsNullOrEmpty(newTargetFrameworkName) && TargetFramework.Empty.Equals(previousContext.ActiveTargetFramework))
                        {
                            // No change
                            return(null);
                        }

                        TargetFramework?newTargetFramework = _targetFrameworkProvider.GetTargetFramework(newTargetFrameworkName);
                        if (previousContext.ActiveTargetFramework.Equals(newTargetFramework))
                        {
                            // No change
                            return(null);
                        }
                    }
                    else
                    {
                        // Check if the current project context is up-to-date for the current active and known project configurations.
                        Assumes.Present(_commonServices.Project.Services.ProjectConfigurationsService);
                        ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;
                        IImmutableSet <ProjectConfiguration> knownProjectConfigurations = await _commonServices.Project.Services.ProjectConfigurationsService.GetKnownProjectConfigurationsAsync();

                        if (knownProjectConfigurations.All(c => c.IsCrossTargeting()) &&
                            HasMatchingTargetFrameworks(activeProjectConfiguration, knownProjectConfigurations))
                        {
                            // No change
                            return(null);
                        }
                    }
                }

                // Force refresh the CPS active project configuration (needs UI thread).
                await _commonServices.ThreadingService.SwitchToUIThread();

                await _activeProjectConfigurationRefreshService.RefreshActiveProjectConfigurationAsync();

                // Create new project context.
                AggregateCrossTargetProjectContext newContext = await _contextProvider.Value.CreateProjectContextAsync();

                Current = newContext;

                return(newContext);

                bool HasMatchingTargetFrameworks(
                    ProjectConfiguration activeProjectConfiguration,
                    IReadOnlyCollection <ProjectConfiguration> knownProjectConfigurations)
                {
                    Assumes.NotNull(previousContext);
                    Assumes.True(activeProjectConfiguration.IsCrossTargeting());

                    TargetFramework?activeTargetFramework = _targetFrameworkProvider.GetTargetFramework(activeProjectConfiguration.Dimensions[ConfigurationGeneral.TargetFrameworkProperty]);

                    if (!previousContext.ActiveTargetFramework.Equals(activeTargetFramework))
                    {
                        // Active target framework is different.
                        return(false);
                    }

                    var targetFrameworkMonikers = knownProjectConfigurations
                                                  .Select(c => c.Dimensions[ConfigurationGeneral.TargetFrameworkProperty])
                                                  .Distinct()
                                                  .ToList();

                    if (targetFrameworkMonikers.Count != previousContext.TargetFrameworks.Length)
                    {
                        // Different number of target frameworks.
                        return(false);
                    }

                    foreach (string targetFrameworkMoniker in targetFrameworkMonikers)
                    {
                        TargetFramework?targetFramework = _targetFrameworkProvider.GetTargetFramework(targetFrameworkMoniker);

                        if (targetFramework == null || !previousContext.TargetFrameworks.Contains(targetFramework))
                        {
                            // Differing TargetFramework
                            return(false);
                        }
                    }

                    return(true);
                }
            }
예제 #12
0
        private async Task <AggregateWorkspaceProjectContext> CreateProjectContextAsyncCore()
        {
            string languageName = await GetLanguageServiceName().ConfigureAwait(false);

            if (string.IsNullOrEmpty(languageName))
            {
                return(null);
            }

            Guid projectGuid = await _projectGuidService.GetProjectGuidAsync()
                               .ConfigureAwait(false);

            string targetPath = await GetTargetPathAsync().ConfigureAwait(false);

            if (string.IsNullOrEmpty(targetPath))
            {
                return(null);
            }


            // TODO: https://github.com/dotnet/roslyn-project-system/issues/353
            await _commonServices.ThreadingService.SwitchToUIThread();

            ProjectData projectData = GetProjectData();

            // Get the set of active configured projects ignoring target framework.
#pragma warning disable CS0618 // Type or member is obsolete
            ImmutableDictionary <string, ConfiguredProject> configuredProjectsMap = await _activeConfiguredProjectsProvider.GetActiveConfiguredProjectsMapAsync().ConfigureAwait(true);

#pragma warning restore CS0618 // Type or member is obsolete

            // Get the unconfigured project host object (shared host object).
            var configuredProjectsToRemove = new HashSet <ConfiguredProject>(_configuredProjectHostObjectsMap.Keys);
            ProjectConfiguration activeProjectConfiguration = _commonServices.ActiveConfiguredProject.ProjectConfiguration;

            ImmutableDictionary <string, IWorkspaceProjectContext> .Builder innerProjectContextsBuilder = ImmutableDictionary.CreateBuilder <string, IWorkspaceProjectContext>();
            string activeTargetFramework = string.Empty;
            IConfiguredProjectHostObject activeIntellisenseProjectHostObject = null;

            foreach (KeyValuePair <string, ConfiguredProject> kvp in configuredProjectsMap)
            {
                string            targetFramework   = kvp.Key;
                ConfiguredProject configuredProject = kvp.Value;
                if (!TryGetConfiguredProjectState(configuredProject, out IWorkspaceProjectContext workspaceProjectContext, out IConfiguredProjectHostObject configuredProjectHostObject))
                {
                    // Get the target path for the configured project.
                    ProjectProperties    projectProperties = configuredProject.Services.ExportProvider.GetExportedValue <ProjectProperties>();
                    ConfigurationGeneral configurationGeneralProperties = await projectProperties.GetConfigurationGeneralPropertiesAsync().ConfigureAwait(true);

                    targetPath = (string)await configurationGeneralProperties.TargetPath.GetValueAsync().ConfigureAwait(true);

                    string targetFrameworkMoniker = (string)await configurationGeneralProperties.TargetFrameworkMoniker.GetValueAsync().ConfigureAwait(true);

                    string workspaceProjectContextId = GetWorkspaceContextId(configuredProject);
                    configuredProjectHostObject = _projectHostProvider.GetConfiguredProjectHostObject(_unconfiguredProjectHostObject, workspaceProjectContextId, targetFrameworkMoniker);

                    // TODO: https://github.com/dotnet/roslyn-project-system/issues/353
                    await _commonServices.ThreadingService.SwitchToUIThread();

                    // NOTE: Despite CreateProjectContext taking a "displayName"; it's actually sets both "WorkspaceProjectContextId", "DisplayName", and default "AssemblyName".
                    // Unlike the latter properties, we cannot change WorkspaceProjectContextId once set, so we pass it as the display name.
                    workspaceProjectContext             = _contextFactory.Value.CreateProjectContext(languageName, workspaceProjectContextId, projectData.FullPath, projectGuid, configuredProjectHostObject, targetPath);
                    workspaceProjectContext.DisplayName = GetDisplayName(configuredProject, projectData, targetFramework);

                    // By default, set "LastDesignTimeBuildSucceeded = false" to turn off diagnostics until first design time build succeeds for this project.
                    workspaceProjectContext.LastDesignTimeBuildSucceeded = false;

                    AddConfiguredProjectState(configuredProject, workspaceProjectContext, configuredProjectHostObject);
                }

                innerProjectContextsBuilder.Add(targetFramework, workspaceProjectContext);

                if (activeIntellisenseProjectHostObject == null && configuredProject.ProjectConfiguration.Equals(activeProjectConfiguration))
                {
                    activeIntellisenseProjectHostObject = configuredProjectHostObject;
                    activeTargetFramework = targetFramework;
                }
            }

            _unconfiguredProjectHostObject.ActiveIntellisenseProjectHostObject = activeIntellisenseProjectHostObject;

            return(new AggregateWorkspaceProjectContext(innerProjectContextsBuilder.ToImmutable(), configuredProjectsMap, activeTargetFramework, _unconfiguredProjectHostObject));
        }
예제 #13
0
 public Init(ConfigurationGeneral configurationGeneral)
 {
     this.mConfigurationGeneral = configurationGeneral;
 }
예제 #14
0
        // Returns the name that is the handshake between Roslyn and the csproj/vbproj
        private async Task <string> GetLanguageServiceName()
        {
            ConfigurationGeneral properties = await _commonServices.ActiveConfiguredProjectProperties.GetConfigurationGeneralPropertiesAsync();

            return((string)await properties.LanguageServiceName.GetValueAsync());
        }