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 = 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.
            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;

            // 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);

            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,
                        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)
            {
                var path = reference.FilePath;
                if (!PathUtilities.IsAbsolute(path))
                {
                    path = PathUtilities.CombineAbsoluteAndRelativePaths(
                        projectDirectory,
                        path);
                }

                projectContext.AddAnalyzerReference(path);
            }

            return (AbstractProject)projectContext;
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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);
            }

            // 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 something has already created this project - it's not deferred, the AnyCode design time build
            // failed so we force loaded it, or we already created a deferred project and we're in a recursive call
            // to find a ProjectReference
            if (_projectMap.TryGetValue(projectId, out var project))
            {
                return(project);
            }

            // If the project system has opted this project out of deferred loading, or AnyCode
            // was unable to get command line info for it, we can't create a project for it.
            // NOTE: We need to check this even though it happened in CreateDeferredProjects
            // because we could be in a recursive call from a project reference below.
            var solution7 = (IVsSolution7)_vsSolution;

            if (DesignTimeBuildFailed(projectInfo) ||
                !solution7.IsDeferredProjectLoadAllowed(projectFilename))
            {
                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());

            OutputToOutputWindow($"\tCreating '{projectName}':\t{commandLineArguments.SourceFiles.Length} source files,\t{commandLineArguments.MetadataReferences.Length} references.");

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

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

            var addedSourceFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

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

            var addedAdditionalFilePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var additionalFile in commandLineArguments.AdditionalFiles)
            {
                if (addedAdditionalFilePaths.Add(additionalFile.Path))
                {
                    projectContext.AddAdditionalFile(additionalFile.Path);
                }
            }

            var metadataReferences     = commandLineArguments.ResolveMetadataReferences(project.CurrentCompilationOptions.MetadataReferenceResolver).AsImmutable();
            var addedProjectReferences = new HashSet <string>();

            foreach (var projectReferencePath in projectInfo.ReferencedProjectFilePaths)
            {
                var referencedProject = TryFindExistingProjectForProjectReference(projectReferencePath, metadataReferences);
                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($"\t\tFailed to create a project for '{projectReferencePath}'.");
                }
            }

            var addedReferencePaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            foreach (var reference in metadataReferences)
            {
                var path = GetReferencePath(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;
                }

                if (addedReferencePaths.Add(path))
                {
                    projectContext.AddMetadataReference(path, reference.Properties);
                }
            }

            var addedAnalyzerPaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

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

                if (addedAnalyzerPaths.Add(path))
                {
                    projectContext.AddAnalyzerReference(path);
                }
            }

            return((AbstractProject)projectContext);
        }
        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;
        }