public void OnAfterCloseSolution()
        {
            AssertIsForeground();

            if (_deferredLoadWasEnabledForLastSolution)
            {
                // Copy to avoid modifying the collection while enumerating
                var loadedProjects = ImmutableProjects.ToList();
                foreach (var p in loadedProjects)
                {
                    p.Disconnect();
                }
            }

            lock (_gate)
            {
                Contract.ThrowIfFalse(_projectMap.Count == 0);
            }

            NotifyWorkspaceHosts(host => host.OnSolutionRemoved());
            NotifyWorkspaceHosts(host => host.ClearSolution());

            lock (_gate)
            {
                _projectPathToIdMap.Clear();
            }

            foreach (var workspaceHost in _workspaceHosts)
            {
                workspaceHost.SolutionClosed();
            }

            _solutionIsClosing = false;
        }
        int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved)
        {
            AssertIsForeground();

            if (IsDeferredSolutionLoadEnabled())
            {
                // Copy to avoid modifying the collection while enumerating
                var loadedProjects = ImmutableProjects.ToList();
                foreach (var p in loadedProjects)
                {
                    p.Disconnect();
                }
            }

            lock (_gate)
            {
                Contract.ThrowIfFalse(_projectMap.Count == 0);
            }

            NotifyWorkspaceHosts_Foreground(host => host.OnSolutionRemoved());
            NotifyWorkspaceHosts_Foreground(host => host.ClearSolution());

            lock (_gate)
            {
                _projectPathToIdMap.Clear();
            }

            foreach (var workspaceHost in _workspaceHosts)
            {
                workspaceHost.SolutionClosed();
            }

            _solutionIsClosing = false;

            return(VSConstants.S_OK);
        }
示例#3
0
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            IAnalyzerAssemblyLoader analyzerAssemblyLoader,
            string projectFilename,
            IReadOnlyDictionary <string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary <string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);

            if (languageName == null)
            {
                return(null);
            }

            if (!allProjectInfos.TryGetValue(projectFilename, out var projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return(null);
            }

            var commandLineParser    = _workspaceServices.GetLanguageServices(languageName).GetService <ICommandLineParserService>();
            var projectDirectory     = PathUtilities.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = PathUtilities.GetFileName(projectFilename, includeExtension: false);

            // `AbstractProject` only sets the filename if it actually exists.  Since we want
            // our ids to match, mimic that behavior here.
            var projectId = File.Exists(projectFilename)
                ? GetOrCreateProjectIdForPath(projectFilename, projectName)
                : GetOrCreateProjectIdForPath(projectName, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            if (_projectMap.TryGetValue(projectId, out var project))
            {
                return(project);
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5 = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;

            // If the index is stale, it might give us a path that doesn't exist anymore that the
            // solution doesn't know about - be resilient to that case.
            Guid projectGuid;

            try
            {
                projectGuid = solution5.GetGuidOfProjectFile(projectFilename);
            }
            catch (ArgumentException)
            {
                var message = $"Failed to get the project guid for '{projectFilename}' from the solution, using  random guid instead.";
                Debug.Fail(message);
                OutputToOutputWindow(message);
                projectGuid = Guid.NewGuid();
            }

            // NOTE: If the indexing service fails for a project, it will give us an *empty*
            // target path, which we aren't prepared to handle.  Instead, convert it to a *null*
            // value, which we do handle.
            var outputPath = projectInfo.TargetPath;

            if (outputPath == string.Empty)
            {
                outputPath = null;
            }

            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: outputPath);

            project = (AbstractProject)projectContext;
            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet <string>();

            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                // NOTE: ImmutableProjects might contain projects for other languages like
                // Xaml, or Typescript where the project file ends up being identical.
                var referencedProject = ImmutableProjects.SingleOrDefault(
                    p => (p.Language == LanguageNames.CSharp || p.Language == LanguageNames.VisualBasic) &&
                    StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        analyzerAssemblyLoader,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver))
            {
                // Some references may fail to be resolved - if they are, we'll still pass them
                // through, in case they come into existence later (they may be built by other
                // parts of the build system).
                var unresolvedReference = reference as UnresolvedMetadataReference;
                var path = unresolvedReference == null
                    ? ((PortableExecutableReference)reference).FilePath
                    : unresolvedReference.Reference;
                if (targetPathsToProjectPaths.TryGetValue(path, out var possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(path, reference.Properties);
            }

            foreach (var reference in commandLineArguments.ResolveAnalyzerReferences(analyzerAssemblyLoader))
            {
                var path = reference.FullPath;
                if (!PathUtilities.IsAbsolute(path))
                {
                    path = PathUtilities.CombineAbsoluteAndRelativePaths(
                        projectDirectory,
                        path);
                }

                projectContext.AddAnalyzerReference(path);
            }

            return((AbstractProject)projectContext);
        }
示例#4
0
        private AbstractProject GetOrCreateProjectFromArgumentsAndReferences(
            IWorkspaceProjectContextFactory workspaceProjectContextFactory,
            string projectFilename,
            IReadOnlyDictionary <string, DeferredProjectInformation> allProjectInfos,
            IReadOnlyDictionary <string, string> targetPathsToProjectPaths)
        {
            var languageName = GetLanguageOfProject(projectFilename);

            if (languageName == null)
            {
                return(null);
            }

            DeferredProjectInformation projectInfo;

            if (!allProjectInfos.TryGetValue(projectFilename, out projectInfo))
            {
                // This could happen if we were called recursively about a dangling P2P reference
                // that isn't actually in the solution.
                return(null);
            }

            var commandLineParser    = _workspaceServices.GetLanguageServices(languageName).GetService <ICommandLineParserService>();
            var projectDirectory     = Path.GetDirectoryName(projectFilename);
            var commandLineArguments = commandLineParser.Parse(
                projectInfo.CommandLineArguments,
                projectDirectory,
                isInteractive: false,
                sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());

            // TODO: Should come from sln file?
            var projectName = Path.GetFileNameWithoutExtension(projectFilename);
            var projectId   = GetOrCreateProjectIdForPath(projectFilename, projectName);

            // See if we've already created this project and we're now in a recursive call to
            // hook up a P2P ref.
            AbstractProject project;

            if (_projectMap.TryGetValue(projectId, out project))
            {
                return(project);
            }

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");
            var solution5      = _serviceProvider.GetService(typeof(SVsSolution)) as IVsSolution5;
            var projectGuid    = solution5.GetGuidOfProjectFile(projectFilename);
            var projectContext = workspaceProjectContextFactory.CreateProjectContext(
                languageName,
                projectName,
                projectFilename,
                projectGuid: projectGuid,
                hierarchy: null,
                binOutputPath: projectInfo.TargetPath);

            projectContext.SetOptions(projectInfo.CommandLineArguments.Join(" "));

            foreach (var sourceFile in commandLineArguments.SourceFiles)
            {
                projectContext.AddSourceFile(sourceFile.Path);
            }

            foreach (var sourceFile in commandLineArguments.AdditionalFiles)
            {
                projectContext.AddAdditionalFile(sourceFile.Path);
            }

            var addedProjectReferences = new HashSet <string>();

            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                var referencedProject = ImmutableProjects.SingleOrDefault(p => StringComparer.OrdinalIgnoreCase.Equals(p.ProjectFilePath, projectReferencePath));
                if (referencedProject == null)
                {
                    referencedProject = GetOrCreateProjectFromArgumentsAndReferences(
                        workspaceProjectContextFactory,
                        projectReferencePath,
                        allProjectInfos,
                        targetPathsToProjectPaths);
                }

                var referencedProjectContext = referencedProject as IWorkspaceProjectContext;
                if (referencedProjectContext != null)
                {
                    // TODO: Can we get the properties from corresponding metadata reference in
                    // commandLineArguments?
                    addedProjectReferences.Add(projectReferencePath);
                    projectContext.AddProjectReference(
                        referencedProjectContext,
                        new MetadataReferenceProperties());
                }
                else if (referencedProject != null)
                {
                    // This project was already created by the regular project system. See if we
                    // can find the matching project somehow.
                    var existingReferenceOutputPath = referencedProject?.BinOutputPath;
                    if (existingReferenceOutputPath != null)
                    {
                        addedProjectReferences.Add(projectReferencePath);
                        projectContext.AddMetadataReference(
                            existingReferenceOutputPath,
                            new MetadataReferenceProperties());
                    }
                }
                else
                {
                    // We don't know how to create this project.  Another language or something?
                    OutputToOutputWindow($"Failed to create a project for '{projectReferencePath}'.");
                }
            }

            foreach (var reference in commandLineArguments.MetadataReferences)
            {
                string possibleProjectReference;
                if (targetPathsToProjectPaths.TryGetValue(reference.Reference, out possibleProjectReference) &&
                    addedProjectReferences.Contains(possibleProjectReference))
                {
                    // We already added a P2P reference for this, we don't need to add the file reference too.
                    continue;
                }

                projectContext.AddMetadataReference(reference.Reference, reference.Properties);
            }

            foreach (var reference in commandLineArguments.AnalyzerReferences)
            {
                projectContext.AddAnalyzerReference(reference.FilePath);
            }

            return((AbstractProject)projectContext);
        }