diff --git a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker.cs b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker.cs
index 273cc15..efa5719 100644
--- a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker.cs
+++ b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker.cs
@@ -13,408 +13,408 @@ namespace SharpIDE.Application.Features.Analysis.ProjectLoader;
public partial class CustomMsBuildProjectLoader
{
- private sealed partial class CustomWorker
- {
- private readonly SolutionServices _solutionServices;
- private readonly DiagnosticReporter _diagnosticReporter;
- private readonly PathResolver _pathResolver;
- private readonly ProjectFileExtensionRegistry _projectFileExtensionRegistry;
- private readonly BuildHostProcessManager _buildHostProcessManager;
- private readonly string _baseDirectory;
-
- ///
- /// An ordered list of paths to project files that should be loaded. In the case of a solution,
- /// this is the list of project file paths in the solution.
- ///
- private readonly ImmutableArray _requestedProjectPaths;
-
- ///
- /// Map of s, project paths, and output file paths.
- ///
- private readonly ProjectMap _projectMap;
-
- ///
- /// Progress reporter.
- ///
- private readonly IProgress? _progress;
-
- ///
- /// Provides options for how failures should be reported when loading requested project files.
- ///
- private readonly DiagnosticReportingOptions _requestedProjectOptions;
-
- ///
- /// Provides options for how failures should be reported when loading any discovered project files.
- ///
- private readonly DiagnosticReportingOptions _discoveredProjectOptions;
-
- ///
- /// When true, metadata is preferred for any project reference unless the referenced project is already loaded
- /// because it was requested.
- ///
- private readonly bool _preferMetadataForReferencesOfDiscoveredProjects;
- private readonly Dictionary _projectIdToFileInfoMap;
- private readonly Dictionary> _projectIdToProjectReferencesMap;
- private readonly Dictionary> _pathToDiscoveredProjectInfosMap;
-
- public CustomWorker(
- SolutionServices services,
- DiagnosticReporter diagnosticReporter,
- PathResolver pathResolver,
- ProjectFileExtensionRegistry projectFileExtensionRegistry,
- BuildHostProcessManager buildHostProcessManager,
- ImmutableArray requestedProjectPaths,
- string baseDirectory,
- ProjectMap? projectMap,
- IProgress? progress,
- DiagnosticReportingOptions requestedProjectOptions,
- DiagnosticReportingOptions discoveredProjectOptions,
- bool preferMetadataForReferencesOfDiscoveredProjects)
- {
- _solutionServices = services;
- _diagnosticReporter = diagnosticReporter;
- _pathResolver = pathResolver;
- _projectFileExtensionRegistry = projectFileExtensionRegistry;
- _buildHostProcessManager = buildHostProcessManager;
- _baseDirectory = baseDirectory;
- _requestedProjectPaths = requestedProjectPaths;
- _projectMap = projectMap ?? ProjectMap.Create();
- _progress = progress;
- _requestedProjectOptions = requestedProjectOptions;
- _discoveredProjectOptions = discoveredProjectOptions;
- _preferMetadataForReferencesOfDiscoveredProjects = preferMetadataForReferencesOfDiscoveredProjects;
- _projectIdToFileInfoMap = [];
- _pathToDiscoveredProjectInfosMap = new Dictionary>(PathUtilities.Comparer);
- _projectIdToProjectReferencesMap = [];
- }
-
- private async Task DoOperationAndReportProgressAsync(ProjectLoadOperation operation, string? projectPath, string? targetFramework, Func> doFunc)
- {
- var watch = _progress != null
- ? Stopwatch.StartNew()
- : null;
-
- TResult result;
- try
- {
- result = await doFunc().ConfigureAwait(false);
- }
- finally
- {
- if (_progress != null && watch != null)
- {
- watch.Stop();
- _progress.Report(new ProjectLoadProgress(projectPath ?? string.Empty, operation, targetFramework, watch.Elapsed));
- }
- }
-
- return result;
- }
-
- public async Task<(ImmutableArray, Dictionary)> LoadAsync(CancellationToken cancellationToken)
- {
- var results = ImmutableArray.CreateBuilder();
- var processedPaths = new HashSet(PathUtilities.Comparer);
-
- foreach (var projectPath in _requestedProjectPaths)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (!_pathResolver.TryGetAbsoluteProjectPath(projectPath, _baseDirectory, _requestedProjectOptions.OnPathFailure, out var absoluteProjectPath))
- {
- continue; // Failure should already be reported.
- }
-
- if (!processedPaths.Add(absoluteProjectPath))
- {
- _diagnosticReporter.Report(
- new WorkspaceDiagnostic(
- WorkspaceDiagnosticKind.Warning,
- string.Format(WorkspaceMSBuildResources.Duplicate_project_discovered_and_skipped_0, absoluteProjectPath)));
-
- continue;
- }
-
- var projectFileInfos = await LoadProjectInfosFromPathAsync(absoluteProjectPath, _requestedProjectOptions, cancellationToken).ConfigureAwait(false);
-
- results.AddRange(projectFileInfos);
- }
-
- foreach (var (projectPath, projectInfos) in _pathToDiscoveredProjectInfosMap)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (!processedPaths.Contains(projectPath))
- {
- results.AddRange(projectInfos);
- }
- }
-
- return (results.ToImmutableAndClear(), _projectIdToFileInfoMap);
- }
-
- private async Task> LoadProjectFileInfosAsync(string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
- {
- if (!_projectFileExtensionRegistry.TryGetLanguageNameFromProjectPath(projectPath, reportingOptions.OnLoaderFailure, out var languageName))
- {
- return []; // Failure should already be reported.
- }
-
- var preferredBuildHostKind = BuildHostProcessManager.GetKindForProject(projectPath);
- var (buildHost, actualBuildHostKind) = await _buildHostProcessManager.GetBuildHostWithFallbackAsync(preferredBuildHostKind, projectPath, cancellationToken).ConfigureAwait(false);
- var projectFile = await DoOperationAndReportProgressAsync(
- ProjectLoadOperation.Evaluate,
- projectPath,
- targetFramework: null,
- () => buildHost.LoadProjectFileAsync(projectPath, languageName, cancellationToken)
- ).ConfigureAwait(false);
-
- // If there were any failures during load, we won't be able to build the project. So, bail early with an empty project.
- var diagnosticItems = await projectFile.GetDiagnosticLogItemsAsync(cancellationToken).ConfigureAwait(false);
- if (diagnosticItems.Any(d => d.Kind == DiagnosticLogItemKind.Error))
- {
- _diagnosticReporter.Report(diagnosticItems);
-
- return [ProjectFileInfo.CreateEmpty(languageName, projectPath)];
- }
-
- var projectFileInfos = await DoOperationAndReportProgressAsync(
- ProjectLoadOperation.Build,
- projectPath,
- targetFramework: null,
- () => projectFile.GetProjectFileInfosAsync(cancellationToken)
- ).ConfigureAwait(false);
-
- var results = ImmutableArray.CreateBuilder(projectFileInfos.Length);
-
- foreach (var projectFileInfo in projectFileInfos)
- {
- // Note: any diagnostics would have been logged to the original project file's log.
-
- results.Add(projectFileInfo);
- }
-
- // We'll go check for any further diagnostics and report them
- diagnosticItems = await projectFile.GetDiagnosticLogItemsAsync(cancellationToken).ConfigureAwait(false);
- _diagnosticReporter.Report(diagnosticItems);
-
- return results.MoveToImmutable();
- }
-
- private async Task> LoadProjectInfosFromPathAsync(
- string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
- {
- if (_projectMap.TryGetProjectInfosByProjectPath(projectPath, out var results) ||
- _pathToDiscoveredProjectInfosMap.TryGetValue(projectPath, out results))
- {
- return results;
- }
-
- var builder = ImmutableArray.CreateBuilder();
-
- var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, reportingOptions, cancellationToken).ConfigureAwait(false);
-
- var idsAndFileInfos = new List<(ProjectId id, ProjectFileInfo fileInfo)>();
-
- foreach (var projectFileInfo in projectFileInfos)
- {
- var projectId = _projectMap.GetOrCreateProjectId(projectFileInfo);
-
- if (_projectIdToFileInfoMap.ContainsKey(projectId))
- {
- // There are multiple projects with the same project path and output path. This can happen
- // if a multi-TFM project does not have unique output file paths for each TFM. In that case,
- // we'll create a new ProjectId to ensure that the project is added to the workspace.
-
- _diagnosticReporter.Report(
- DiagnosticReportingMode.Log,
- string.Format(WorkspaceMSBuildResources.Found_project_with_the_same_file_path_and_output_path_as_another_project_0, projectFileInfo.FilePath));
-
- projectId = ProjectId.CreateNewId(debugName: projectFileInfo.FilePath);
- }
-
- idsAndFileInfos.Add((projectId, projectFileInfo));
- _projectIdToFileInfoMap.Add(projectId, projectFileInfo);
- }
-
- // If this project resulted in more than a single project, a discriminator (e.g. TFM) should be
- // added to the project name.
- var addDiscriminator = idsAndFileInfos.Count > 1;
-
- foreach (var (id, fileInfo) in idsAndFileInfos)
- {
- var projectInfo = await CreateProjectInfoAsync(fileInfo, id, addDiscriminator, cancellationToken).ConfigureAwait(false);
-
- builder.Add(projectInfo);
- _projectMap.AddProjectInfo(projectInfo);
- }
-
- results = builder.ToImmutable();
-
- _pathToDiscoveredProjectInfosMap.Add(projectPath, results);
-
- return results;
- }
-
- private Task CreateProjectInfoAsync(ProjectFileInfo projectFileInfo, ProjectId projectId, bool addDiscriminator, CancellationToken cancellationToken)
- {
- var language = projectFileInfo.Language;
- var projectPath = projectFileInfo.FilePath;
- var projectName = Path.GetFileNameWithoutExtension(projectPath) ?? string.Empty;
- if (addDiscriminator && !RoslynString.IsNullOrWhiteSpace(projectFileInfo.TargetFramework))
- {
- projectName += "(" + projectFileInfo.TargetFramework + ")";
- }
-
- var version = projectPath is null
- ? VersionStamp.Default
- : VersionStamp.Create(FileUtilities.GetFileTimeStamp(projectPath));
-
- if (projectFileInfo.IsEmpty)
- {
- var assemblyName = GetAssemblyNameFromProjectPath(projectPath);
-
- var parseOptions = GetLanguageService(language)
- ?.GetDefaultParseOptions();
- var compilationOptions = GetLanguageService(language)
- ?.GetDefaultCompilationOptions();
-
- return Task.FromResult(
- ProjectInfo.Create(
- new ProjectInfo.ProjectAttributes(
- projectId,
- version,
- name: projectName,
- assemblyName: assemblyName,
- language: language,
- compilationOutputInfo: new CompilationOutputInfo(projectFileInfo.IntermediateOutputFilePath, projectFileInfo.GeneratedFilesOutputDirectory),
- checksumAlgorithm: SourceHashAlgorithms.Default,
- outputFilePath: projectFileInfo.OutputFilePath,
- outputRefFilePath: projectFileInfo.OutputRefFilePath,
- filePath: projectPath),
- compilationOptions: compilationOptions,
- parseOptions: parseOptions));
- }
-
- return DoOperationAndReportProgressAsync(ProjectLoadOperation.Resolve, projectPath, projectFileInfo.TargetFramework, async () =>
- {
- var projectDirectory = Path.GetDirectoryName(projectPath);
-
- // parse command line arguments
- var commandLineParser = GetLanguageService(projectFileInfo.Language);
-
- if (commandLineParser is null)
- {
- var message = string.Format(WorkspaceMSBuildResources.Unable_to_find_a_0_for_1, nameof(ICommandLineParserService), projectFileInfo.Language);
- throw new Exception(message);
- }
-
- var commandLineArgs = commandLineParser.Parse(
- arguments: projectFileInfo.CommandLineArgs,
- baseDirectory: projectDirectory,
- isInteractive: false,
- sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
-
- var assemblyName = commandLineArgs.CompilationName;
- if (RoslynString.IsNullOrWhiteSpace(assemblyName))
- {
- // if there isn't an assembly name, make one from the file path.
- // Note: This may not be necessary any longer if the command line args
- // always produce a valid compilation name.
- assemblyName = GetAssemblyNameFromProjectPath(projectPath);
- }
-
- // Ensure sure that doc-comments are parsed
- var parseOptions = commandLineArgs.ParseOptions;
- if (parseOptions.DocumentationMode == DocumentationMode.None)
- {
- parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.Parse);
- }
-
- // add all the extra options that are really behavior overrides
- var metadataService = GetWorkspaceService();
- var compilationOptions = commandLineArgs.CompilationOptions
- .WithXmlReferenceResolver(new XmlFileResolver(projectDirectory))
- .WithSourceReferenceResolver(new SourceFileResolver([], projectDirectory))
- // TODO: https://github.com/dotnet/roslyn/issues/4967
- .WithMetadataReferenceResolver(new WorkspaceMetadataFileReferenceResolver(metadataService, new RelativePathResolver([], projectDirectory)))
- .WithStrongNameProvider(new DesktopStrongNameProvider(commandLineArgs.KeyFileSearchPaths, Path.GetTempPath()))
- .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
-
- var documents = CreateDocumentInfos(projectFileInfo.Documents, projectId, commandLineArgs.Encoding);
- var additionalDocuments = CreateDocumentInfos(projectFileInfo.AdditionalDocuments, projectId, commandLineArgs.Encoding);
- var analyzerConfigDocuments = CreateDocumentInfos(projectFileInfo.AnalyzerConfigDocuments, projectId, commandLineArgs.Encoding);
- CheckForDuplicateDocuments(documents.Concat(additionalDocuments).Concat(analyzerConfigDocuments), projectPath, projectId);
-
- var analyzerReferences = ResolveAnalyzerReferences(commandLineArgs);
-
- var resolvedReferences = await ResolveReferencesAsync(projectId, projectFileInfo, commandLineArgs, cancellationToken).ConfigureAwait(false);
-
- return ProjectInfo.Create(
- new ProjectInfo.ProjectAttributes(
- projectId,
- version,
- projectName,
- assemblyName,
- language,
- compilationOutputInfo: new CompilationOutputInfo(projectFileInfo.IntermediateOutputFilePath, projectFileInfo.GeneratedFilesOutputDirectory),
- checksumAlgorithm: commandLineArgs.ChecksumAlgorithm,
- filePath: projectPath,
- outputFilePath: projectFileInfo.OutputFilePath,
- outputRefFilePath: projectFileInfo.OutputRefFilePath,
- isSubmission: false),
- compilationOptions: compilationOptions,
- parseOptions: parseOptions,
- documents: documents,
- projectReferences: resolvedReferences.ProjectReferences,
- metadataReferences: resolvedReferences.MetadataReferences,
- analyzerReferences: analyzerReferences,
- additionalDocuments: additionalDocuments,
- hostObjectType: null)
- .WithDefaultNamespace(projectFileInfo.DefaultNamespace)
- .WithAnalyzerConfigDocuments(analyzerConfigDocuments);
- });
- }
-
- private static string GetAssemblyNameFromProjectPath(string? projectFilePath)
- {
- var assemblyName = Path.GetFileNameWithoutExtension(projectFilePath);
-
- // if this is still unreasonable, use a fixed name.
- if (RoslynString.IsNullOrWhiteSpace(assemblyName))
- {
- assemblyName = "assembly";
- }
-
- return assemblyName;
- }
-
- private IEnumerable ResolveAnalyzerReferences(CommandLineArguments commandLineArgs)
- {
- // The one line that is changed from the original Roslyn code:
- var analyzerAssemblyLoaderProvider = GetWorkspaceService();
- if (analyzerAssemblyLoaderProvider is null)
- {
- var message = string.Format(WorkspaceMSBuildResources.Unable_to_find_0, nameof(IAnalyzerService));
- throw new Exception(message);
- }
-
- var analyzerLoader = analyzerAssemblyLoaderProvider.SharedShadowCopyLoader;
-
- foreach (var path in commandLineArgs.AnalyzerReferences.Select(r => r.FilePath))
- {
- string? fullPath;
-
- if (PathUtilities.IsAbsolute(path))
- {
- fullPath = FileUtilities.TryNormalizeAbsolutePath(path);
-
- if (fullPath != null && File.Exists(fullPath))
- {
- analyzerLoader.AddDependencyLocation(fullPath);
- }
- }
- }
+ private sealed partial class CustomWorker
+ {
+ private readonly SolutionServices _solutionServices;
+ private readonly DiagnosticReporter _diagnosticReporter;
+ private readonly PathResolver _pathResolver;
+ private readonly ProjectFileExtensionRegistry _projectFileExtensionRegistry;
+ private readonly BuildHostProcessManager _buildHostProcessManager;
+ private readonly string _baseDirectory;
+
+ ///
+ /// An ordered list of paths to project files that should be loaded. In the case of a solution,
+ /// this is the list of project file paths in the solution.
+ ///
+ private readonly ImmutableArray _requestedProjectPaths;
+
+ ///
+ /// Map of s, project paths, and output file paths.
+ ///
+ private readonly ProjectMap _projectMap;
+
+ ///
+ /// Progress reporter.
+ ///
+ private readonly IProgress? _progress;
+
+ ///
+ /// Provides options for how failures should be reported when loading requested project files.
+ ///
+ private readonly DiagnosticReportingOptions _requestedProjectOptions;
+
+ ///
+ /// Provides options for how failures should be reported when loading any discovered project files.
+ ///
+ private readonly DiagnosticReportingOptions _discoveredProjectOptions;
+
+ ///
+ /// When true, metadata is preferred for any project reference unless the referenced project is already loaded
+ /// because it was requested.
+ ///
+ private readonly bool _preferMetadataForReferencesOfDiscoveredProjects;
+ private readonly Dictionary _projectIdToFileInfoMap;
+ private readonly Dictionary> _projectIdToProjectReferencesMap;
+ private readonly Dictionary> _pathToDiscoveredProjectInfosMap;
+
+ public CustomWorker(
+ SolutionServices services,
+ DiagnosticReporter diagnosticReporter,
+ PathResolver pathResolver,
+ ProjectFileExtensionRegistry projectFileExtensionRegistry,
+ BuildHostProcessManager buildHostProcessManager,
+ ImmutableArray requestedProjectPaths,
+ string baseDirectory,
+ ProjectMap? projectMap,
+ IProgress? progress,
+ DiagnosticReportingOptions requestedProjectOptions,
+ DiagnosticReportingOptions discoveredProjectOptions,
+ bool preferMetadataForReferencesOfDiscoveredProjects)
+ {
+ _solutionServices = services;
+ _diagnosticReporter = diagnosticReporter;
+ _pathResolver = pathResolver;
+ _projectFileExtensionRegistry = projectFileExtensionRegistry;
+ _buildHostProcessManager = buildHostProcessManager;
+ _baseDirectory = baseDirectory;
+ _requestedProjectPaths = requestedProjectPaths;
+ _projectMap = projectMap ?? ProjectMap.Create();
+ _progress = progress;
+ _requestedProjectOptions = requestedProjectOptions;
+ _discoveredProjectOptions = discoveredProjectOptions;
+ _preferMetadataForReferencesOfDiscoveredProjects = preferMetadataForReferencesOfDiscoveredProjects;
+ _projectIdToFileInfoMap = [];
+ _pathToDiscoveredProjectInfosMap = new Dictionary>(PathUtilities.Comparer);
+ _projectIdToProjectReferencesMap = [];
+ }
+
+ private async Task DoOperationAndReportProgressAsync(ProjectLoadOperation operation, string? projectPath, string? targetFramework, Func> doFunc)
+ {
+ var watch = _progress != null
+ ? Stopwatch.StartNew()
+ : null;
+
+ TResult result;
+ try
+ {
+ result = await doFunc().ConfigureAwait(false);
+ }
+ finally
+ {
+ if (_progress != null && watch != null)
+ {
+ watch.Stop();
+ _progress.Report(new ProjectLoadProgress(projectPath ?? string.Empty, operation, targetFramework, watch.Elapsed));
+ }
+ }
+
+ return result;
+ }
+
+ public async Task<(ImmutableArray, Dictionary)> LoadAsync(CancellationToken cancellationToken)
+ {
+ var results = ImmutableArray.CreateBuilder();
+ var processedPaths = new HashSet(PathUtilities.Comparer);
+
+ foreach (var projectPath in _requestedProjectPaths)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (!_pathResolver.TryGetAbsoluteProjectPath(projectPath, _baseDirectory, _requestedProjectOptions.OnPathFailure, out var absoluteProjectPath))
+ {
+ continue; // Failure should already be reported.
+ }
+
+ if (!processedPaths.Add(absoluteProjectPath))
+ {
+ _diagnosticReporter.Report(
+ new WorkspaceDiagnostic(
+ WorkspaceDiagnosticKind.Warning,
+ string.Format(WorkspaceMSBuildResources.Duplicate_project_discovered_and_skipped_0, absoluteProjectPath)));
+
+ continue;
+ }
+
+ var projectFileInfos = await LoadProjectInfosFromPathAsync(absoluteProjectPath, _requestedProjectOptions, cancellationToken).ConfigureAwait(false);
+
+ results.AddRange(projectFileInfos);
+ }
+
+ foreach (var (projectPath, projectInfos) in _pathToDiscoveredProjectInfosMap)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (!processedPaths.Contains(projectPath))
+ {
+ results.AddRange(projectInfos);
+ }
+ }
+
+ return (results.ToImmutableAndClear(), _projectIdToFileInfoMap);
+ }
+
+ private async Task> LoadProjectFileInfosAsync(string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
+ {
+ if (!_projectFileExtensionRegistry.TryGetLanguageNameFromProjectPath(projectPath, reportingOptions.OnLoaderFailure, out var languageName))
+ {
+ return []; // Failure should already be reported.
+ }
+
+ var preferredBuildHostKind = BuildHostProcessManager.GetKindForProject(projectPath);
+ var (buildHost, actualBuildHostKind) = await _buildHostProcessManager.GetBuildHostWithFallbackAsync(preferredBuildHostKind, projectPath, cancellationToken).ConfigureAwait(false);
+ var projectFile = await DoOperationAndReportProgressAsync(
+ ProjectLoadOperation.Evaluate,
+ projectPath,
+ targetFramework: null,
+ () => buildHost.LoadProjectFileAsync(projectPath, languageName, cancellationToken)
+ ).ConfigureAwait(false);
+
+ // If there were any failures during load, we won't be able to build the project. So, bail early with an empty project.
+ var diagnosticItems = await projectFile.GetDiagnosticLogItemsAsync(cancellationToken).ConfigureAwait(false);
+ if (diagnosticItems.Any(d => d.Kind == DiagnosticLogItemKind.Error))
+ {
+ _diagnosticReporter.Report(diagnosticItems);
+
+ return [ProjectFileInfo.CreateEmpty(languageName, projectPath)];
+ }
+
+ var projectFileInfos = await DoOperationAndReportProgressAsync(
+ ProjectLoadOperation.Build,
+ projectPath,
+ targetFramework: null,
+ () => projectFile.GetProjectFileInfosAsync(cancellationToken)
+ ).ConfigureAwait(false);
+
+ var results = ImmutableArray.CreateBuilder(projectFileInfos.Length);
+
+ foreach (var projectFileInfo in projectFileInfos)
+ {
+ // Note: any diagnostics would have been logged to the original project file's log.
+
+ results.Add(projectFileInfo);
+ }
+
+ // We'll go check for any further diagnostics and report them
+ diagnosticItems = await projectFile.GetDiagnosticLogItemsAsync(cancellationToken).ConfigureAwait(false);
+ _diagnosticReporter.Report(diagnosticItems);
+
+ return results.MoveToImmutable();
+ }
+
+ private async Task> LoadProjectInfosFromPathAsync(
+ string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
+ {
+ if (_projectMap.TryGetProjectInfosByProjectPath(projectPath, out var results) ||
+ _pathToDiscoveredProjectInfosMap.TryGetValue(projectPath, out results))
+ {
+ return results;
+ }
+
+ var builder = ImmutableArray.CreateBuilder();
+
+ var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, reportingOptions, cancellationToken).ConfigureAwait(false);
+
+ var idsAndFileInfos = new List<(ProjectId id, ProjectFileInfo fileInfo)>();
+
+ foreach (var projectFileInfo in projectFileInfos)
+ {
+ var projectId = _projectMap.GetOrCreateProjectId(projectFileInfo);
+
+ if (_projectIdToFileInfoMap.ContainsKey(projectId))
+ {
+ // There are multiple projects with the same project path and output path. This can happen
+ // if a multi-TFM project does not have unique output file paths for each TFM. In that case,
+ // we'll create a new ProjectId to ensure that the project is added to the workspace.
+
+ _diagnosticReporter.Report(
+ DiagnosticReportingMode.Log,
+ string.Format(WorkspaceMSBuildResources.Found_project_with_the_same_file_path_and_output_path_as_another_project_0, projectFileInfo.FilePath));
+
+ projectId = ProjectId.CreateNewId(debugName: projectFileInfo.FilePath);
+ }
+
+ idsAndFileInfos.Add((projectId, projectFileInfo));
+ _projectIdToFileInfoMap.Add(projectId, projectFileInfo);
+ }
+
+ // If this project resulted in more than a single project, a discriminator (e.g. TFM) should be
+ // added to the project name.
+ var addDiscriminator = idsAndFileInfos.Count > 1;
+
+ foreach (var (id, fileInfo) in idsAndFileInfos)
+ {
+ var projectInfo = await CreateProjectInfoAsync(fileInfo, id, addDiscriminator, cancellationToken).ConfigureAwait(false);
+
+ builder.Add(projectInfo);
+ _projectMap.AddProjectInfo(projectInfo);
+ }
+
+ results = builder.ToImmutable();
+
+ _pathToDiscoveredProjectInfosMap.Add(projectPath, results);
+
+ return results;
+ }
+
+ private Task CreateProjectInfoAsync(ProjectFileInfo projectFileInfo, ProjectId projectId, bool addDiscriminator, CancellationToken cancellationToken)
+ {
+ var language = projectFileInfo.Language;
+ var projectPath = projectFileInfo.FilePath;
+ var projectName = Path.GetFileNameWithoutExtension(projectPath) ?? string.Empty;
+ if (addDiscriminator && !RoslynString.IsNullOrWhiteSpace(projectFileInfo.TargetFramework))
+ {
+ projectName += "(" + projectFileInfo.TargetFramework + ")";
+ }
+
+ var version = projectPath is null
+ ? VersionStamp.Default
+ : VersionStamp.Create(FileUtilities.GetFileTimeStamp(projectPath));
+
+ if (projectFileInfo.IsEmpty)
+ {
+ var assemblyName = GetAssemblyNameFromProjectPath(projectPath);
+
+ var parseOptions = GetLanguageService(language)
+ ?.GetDefaultParseOptions();
+ var compilationOptions = GetLanguageService(language)
+ ?.GetDefaultCompilationOptions();
+
+ return Task.FromResult(
+ ProjectInfo.Create(
+ new ProjectInfo.ProjectAttributes(
+ projectId,
+ version,
+ name: projectName,
+ assemblyName: assemblyName,
+ language: language,
+ compilationOutputInfo: new CompilationOutputInfo(projectFileInfo.IntermediateOutputFilePath, projectFileInfo.GeneratedFilesOutputDirectory),
+ checksumAlgorithm: SourceHashAlgorithms.Default,
+ outputFilePath: projectFileInfo.OutputFilePath,
+ outputRefFilePath: projectFileInfo.OutputRefFilePath,
+ filePath: projectPath),
+ compilationOptions: compilationOptions,
+ parseOptions: parseOptions));
+ }
+
+ return DoOperationAndReportProgressAsync(ProjectLoadOperation.Resolve, projectPath, projectFileInfo.TargetFramework, async () =>
+ {
+ var projectDirectory = Path.GetDirectoryName(projectPath);
+
+ // parse command line arguments
+ var commandLineParser = GetLanguageService(projectFileInfo.Language);
+
+ if (commandLineParser is null)
+ {
+ var message = string.Format(WorkspaceMSBuildResources.Unable_to_find_a_0_for_1, nameof(ICommandLineParserService), projectFileInfo.Language);
+ throw new Exception(message);
+ }
+
+ var commandLineArgs = commandLineParser.Parse(
+ arguments: projectFileInfo.CommandLineArgs,
+ baseDirectory: projectDirectory,
+ isInteractive: false,
+ sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
+
+ var assemblyName = commandLineArgs.CompilationName;
+ if (RoslynString.IsNullOrWhiteSpace(assemblyName))
+ {
+ // if there isn't an assembly name, make one from the file path.
+ // Note: This may not be necessary any longer if the command line args
+ // always produce a valid compilation name.
+ assemblyName = GetAssemblyNameFromProjectPath(projectPath);
+ }
+
+ // Ensure sure that doc-comments are parsed
+ var parseOptions = commandLineArgs.ParseOptions;
+ if (parseOptions.DocumentationMode == DocumentationMode.None)
+ {
+ parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.Parse);
+ }
+
+ // add all the extra options that are really behavior overrides
+ var metadataService = GetWorkspaceService();
+ var compilationOptions = commandLineArgs.CompilationOptions
+ .WithXmlReferenceResolver(new XmlFileResolver(projectDirectory))
+ .WithSourceReferenceResolver(new SourceFileResolver([], projectDirectory))
+ // TODO: https://github.com/dotnet/roslyn/issues/4967
+ .WithMetadataReferenceResolver(new WorkspaceMetadataFileReferenceResolver(metadataService, new RelativePathResolver([], projectDirectory)))
+ .WithStrongNameProvider(new DesktopStrongNameProvider(commandLineArgs.KeyFileSearchPaths, Path.GetTempPath()))
+ .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
+
+ var documents = CreateDocumentInfos(projectFileInfo.Documents, projectId, commandLineArgs.Encoding);
+ var additionalDocuments = CreateDocumentInfos(projectFileInfo.AdditionalDocuments, projectId, commandLineArgs.Encoding);
+ var analyzerConfigDocuments = CreateDocumentInfos(projectFileInfo.AnalyzerConfigDocuments, projectId, commandLineArgs.Encoding);
+ CheckForDuplicateDocuments(documents.Concat(additionalDocuments).Concat(analyzerConfigDocuments), projectPath, projectId);
+
+ var analyzerReferences = ResolveAnalyzerReferences(commandLineArgs);
+
+ var resolvedReferences = await ResolveReferencesAsync(projectId, projectFileInfo, commandLineArgs, cancellationToken).ConfigureAwait(false);
+
+ return ProjectInfo.Create(
+ new ProjectInfo.ProjectAttributes(
+ projectId,
+ version,
+ projectName,
+ assemblyName,
+ language,
+ compilationOutputInfo: new CompilationOutputInfo(projectFileInfo.IntermediateOutputFilePath, projectFileInfo.GeneratedFilesOutputDirectory),
+ checksumAlgorithm: commandLineArgs.ChecksumAlgorithm,
+ filePath: projectPath,
+ outputFilePath: projectFileInfo.OutputFilePath,
+ outputRefFilePath: projectFileInfo.OutputRefFilePath,
+ isSubmission: false),
+ compilationOptions: compilationOptions,
+ parseOptions: parseOptions,
+ documents: documents,
+ projectReferences: resolvedReferences.ProjectReferences,
+ metadataReferences: resolvedReferences.MetadataReferences,
+ analyzerReferences: analyzerReferences,
+ additionalDocuments: additionalDocuments,
+ hostObjectType: null)
+ .WithDefaultNamespace(projectFileInfo.DefaultNamespace)
+ .WithAnalyzerConfigDocuments(analyzerConfigDocuments);
+ });
+ }
+
+ private static string GetAssemblyNameFromProjectPath(string? projectFilePath)
+ {
+ var assemblyName = Path.GetFileNameWithoutExtension(projectFilePath);
+
+ // if this is still unreasonable, use a fixed name.
+ if (RoslynString.IsNullOrWhiteSpace(assemblyName))
+ {
+ assemblyName = "assembly";
+ }
+
+ return assemblyName;
+ }
+
+ private IEnumerable ResolveAnalyzerReferences(CommandLineArguments commandLineArgs)
+ {
+ // The one line that is changed from the original Roslyn code:
+ var analyzerAssemblyLoaderProvider = GetWorkspaceService();
+ if (analyzerAssemblyLoaderProvider is null)
+ {
+ var message = string.Format(WorkspaceMSBuildResources.Unable_to_find_0, nameof(IAnalyzerService));
+ throw new Exception(message);
+ }
+
+ var analyzerLoader = analyzerAssemblyLoaderProvider.SharedShadowCopyLoader;
+
+ foreach (var path in commandLineArgs.AnalyzerReferences.Select(r => r.FilePath))
+ {
+ string? fullPath;
+
+ if (PathUtilities.IsAbsolute(path))
+ {
+ fullPath = FileUtilities.TryNormalizeAbsolutePath(path);
+
+ if (fullPath != null && File.Exists(fullPath))
+ {
+ analyzerLoader.AddDependencyLocation(fullPath);
+ }
+ }
+ }
var analyzerReferences = commandLineArgs.ResolveAnalyzerReferences(analyzerLoader).Distinct(Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.AnalyzerReferencePathComparer.Instance);
var isolatedReferences = IsolatedAnalyzerReferenceSet.CreateIsolatedAnalyzerReferencesAsync(
@@ -424,80 +424,80 @@ public partial class CustomMsBuildProjectLoader
CancellationToken.None).VerifyCompleted();
return isolatedReferences;
- }
+ }
- private ImmutableArray CreateDocumentInfos(IReadOnlyList documentFileInfos, ProjectId projectId, Encoding? encoding)
- {
- var results = new FixedSizeArrayBuilder(documentFileInfos.Count);
+ private ImmutableArray CreateDocumentInfos(IReadOnlyList documentFileInfos, ProjectId projectId, Encoding? encoding)
+ {
+ var results = new FixedSizeArrayBuilder(documentFileInfos.Count);
- foreach (var info in documentFileInfos)
- {
- GetDocumentNameAndFolders(info.LogicalPath, out var name, out var folders);
+ foreach (var info in documentFileInfos)
+ {
+ GetDocumentNameAndFolders(info.LogicalPath, out var name, out var folders);
- var documentInfo = DocumentInfo.Create(
- DocumentId.CreateNewId(projectId, debugName: info.FilePath),
- name,
- folders,
- SourceCodeKind.Regular,
- new WorkspaceFileTextLoader(_solutionServices, info.FilePath, encoding),
- info.FilePath,
- info.IsGenerated);
+ var documentInfo = DocumentInfo.Create(
+ DocumentId.CreateNewId(projectId, debugName: info.FilePath),
+ name,
+ folders,
+ SourceCodeKind.Regular,
+ new WorkspaceFileTextLoader(_solutionServices, info.FilePath, encoding),
+ info.FilePath,
+ info.IsGenerated);
- results.Add(documentInfo);
- }
+ results.Add(documentInfo);
+ }
- return results.MoveToImmutable();
- }
+ return results.MoveToImmutable();
+ }
- private static readonly char[] s_directorySplitChars = [Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar];
+ private static readonly char[] s_directorySplitChars = [Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar];
- private static void GetDocumentNameAndFolders(string logicalPath, out string name, out ImmutableArray folders)
- {
- var pathNames = logicalPath.Split(s_directorySplitChars, StringSplitOptions.RemoveEmptyEntries);
- if (pathNames.Length > 0)
- {
- folders = pathNames.Length > 1
- ? [.. pathNames.Take(pathNames.Length - 1)]
- : [];
+ private static void GetDocumentNameAndFolders(string logicalPath, out string name, out ImmutableArray folders)
+ {
+ var pathNames = logicalPath.Split(s_directorySplitChars, StringSplitOptions.RemoveEmptyEntries);
+ if (pathNames.Length > 0)
+ {
+ folders = pathNames.Length > 1
+ ? [.. pathNames.Take(pathNames.Length - 1)]
+ : [];
- name = pathNames[^1];
- }
- else
- {
- name = logicalPath;
- folders = [];
- }
- }
+ name = pathNames[^1];
+ }
+ else
+ {
+ name = logicalPath;
+ folders = [];
+ }
+ }
- private void CheckForDuplicateDocuments(ImmutableArray documents, string? projectFilePath, ProjectId projectId)
- {
- var paths = new HashSet(PathUtilities.Comparer);
- foreach (var doc in documents)
- {
- if (doc.FilePath is null)
- continue;
+ private void CheckForDuplicateDocuments(ImmutableArray documents, string? projectFilePath, ProjectId projectId)
+ {
+ var paths = new HashSet(PathUtilities.Comparer);
+ foreach (var doc in documents)
+ {
+ if (doc.FilePath is null)
+ continue;
- if (paths.Contains(doc.FilePath))
- {
- var message = string.Format(WorkspacesResources.Duplicate_source_file_0_in_project_1, doc.FilePath, projectFilePath);
- var diagnostic = new ProjectDiagnostic(WorkspaceDiagnosticKind.Warning, message, projectId);
+ if (paths.Contains(doc.FilePath))
+ {
+ var message = string.Format(WorkspacesResources.Duplicate_source_file_0_in_project_1, doc.FilePath, projectFilePath);
+ var diagnostic = new ProjectDiagnostic(WorkspaceDiagnosticKind.Warning, message, projectId);
- _diagnosticReporter.Report(diagnostic);
- }
+ _diagnosticReporter.Report(diagnostic);
+ }
- paths.Add(doc.FilePath);
- }
- }
+ paths.Add(doc.FilePath);
+ }
+ }
- private TLanguageService? GetLanguageService(string languageName)
- where TLanguageService : ILanguageService
- => _solutionServices
- .GetLanguageServices(languageName)
- .GetService();
+ private TLanguageService? GetLanguageService(string languageName)
+ where TLanguageService : ILanguageService
+ => _solutionServices
+ .GetLanguageServices(languageName)
+ .GetService();
- private TWorkspaceService? GetWorkspaceService()
- where TWorkspaceService : IWorkspaceService
- => _solutionServices
- .GetService();
- }
+ private TWorkspaceService? GetWorkspaceService()
+ where TWorkspaceService : IWorkspaceService
+ => _solutionServices
+ .GetService();
+ }
}
diff --git a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker_ResolveReferences.cs b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker_ResolveReferences.cs
index 84e8f05..dc6a0d8 100644
--- a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker_ResolveReferences.cs
+++ b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.Worker_ResolveReferences.cs
@@ -9,400 +9,400 @@ namespace SharpIDE.Application.Features.Analysis.ProjectLoader;
public partial class CustomMsBuildProjectLoader
{
- private sealed partial class CustomWorker
- {
- private readonly struct ResolvedReferences
- {
- public ImmutableHashSet ProjectReferences { get; }
- public ImmutableArray MetadataReferences { get; }
+ private sealed partial class CustomWorker
+ {
+ private readonly struct ResolvedReferences
+ {
+ public ImmutableHashSet ProjectReferences { get; }
+ public ImmutableArray MetadataReferences { get; }
- public ResolvedReferences(ImmutableHashSet projectReferences, ImmutableArray metadataReferences)
- {
- ProjectReferences = projectReferences;
- MetadataReferences = metadataReferences;
- }
- }
+ public ResolvedReferences(ImmutableHashSet projectReferences, ImmutableArray metadataReferences)
+ {
+ ProjectReferences = projectReferences;
+ MetadataReferences = metadataReferences;
+ }
+ }
- ///
- /// This type helps produces lists of metadata and project references. Initially, it contains a list of metadata references.
- /// As project references are added, the metadata references that match those project references are removed.
- ///
- private sealed class ResolvedReferencesBuilder
- {
- ///
- /// The full list of s.
- ///
- private readonly ImmutableArray _metadataReferences;
+ ///
+ /// This type helps produces lists of metadata and project references. Initially, it contains a list of metadata references.
+ /// As project references are added, the metadata references that match those project references are removed.
+ ///
+ private sealed class ResolvedReferencesBuilder
+ {
+ ///
+ /// The full list of s.
+ ///
+ private readonly ImmutableArray _metadataReferences;
- ///
- /// A map of every metadata reference file paths to a set of indices whether than file path
- /// exists in the list. It is expected that there may be multiple metadata references for the
- /// same file path in the case where multiple extern aliases are provided.
- ///
- private readonly ImmutableDictionary> _pathToIndicesMap;
+ ///
+ /// A map of every metadata reference file paths to a set of indices whether than file path
+ /// exists in the list. It is expected that there may be multiple metadata references for the
+ /// same file path in the case where multiple extern aliases are provided.
+ ///
+ private readonly ImmutableDictionary> _pathToIndicesMap;
- ///
- /// A set of indices into that are to be removed.
- ///
- private readonly HashSet _indicesToRemove;
+ ///
+ /// A set of indices into that are to be removed.
+ ///
+ private readonly HashSet _indicesToRemove;
- private readonly ImmutableHashSet.Builder _projectReferences;
+ private readonly ImmutableHashSet.Builder _projectReferences;
- public ResolvedReferencesBuilder(IEnumerable metadataReferences)
- {
- _metadataReferences = [.. metadataReferences];
- _pathToIndicesMap = CreatePathToIndexMap(_metadataReferences);
- _indicesToRemove = [];
- _projectReferences = ImmutableHashSet.CreateBuilder();
- }
+ public ResolvedReferencesBuilder(IEnumerable metadataReferences)
+ {
+ _metadataReferences = [.. metadataReferences];
+ _pathToIndicesMap = CreatePathToIndexMap(_metadataReferences);
+ _indicesToRemove = [];
+ _projectReferences = ImmutableHashSet.CreateBuilder();
+ }
- private static ImmutableDictionary> CreatePathToIndexMap(ImmutableArray metadataReferences)
- {
- var builder = ImmutableDictionary.CreateBuilder>(PathUtilities.Comparer);
+ private static ImmutableDictionary> CreatePathToIndexMap(ImmutableArray metadataReferences)
+ {
+ var builder = ImmutableDictionary.CreateBuilder>(PathUtilities.Comparer);
- for (var index = 0; index < metadataReferences.Length; index++)
- {
- var filePath = GetFilePath(metadataReferences[index]);
- if (filePath != null)
- {
- builder.MultiAdd(filePath, index);
- }
- }
+ for (var index = 0; index < metadataReferences.Length; index++)
+ {
+ var filePath = GetFilePath(metadataReferences[index]);
+ if (filePath != null)
+ {
+ builder.MultiAdd(filePath, index);
+ }
+ }
- return builder.ToImmutable();
- }
+ return builder.ToImmutable();
+ }
- private static string? GetFilePath(MetadataReference metadataReference)
- {
- return metadataReference switch
- {
- PortableExecutableReference portableExecutableReference => portableExecutableReference.FilePath,
- UnresolvedMetadataReference unresolvedMetadataReference => unresolvedMetadataReference.Reference,
- _ => null,
- };
- }
+ private static string? GetFilePath(MetadataReference metadataReference)
+ {
+ return metadataReference switch
+ {
+ PortableExecutableReference portableExecutableReference => portableExecutableReference.FilePath,
+ UnresolvedMetadataReference unresolvedMetadataReference => unresolvedMetadataReference.Reference,
+ _ => null,
+ };
+ }
- public void AddProjectReference(ProjectReference projectReference)
- {
- _projectReferences.Add(projectReference);
- }
+ public void AddProjectReference(ProjectReference projectReference)
+ {
+ _projectReferences.Add(projectReference);
+ }
- public void SwapMetadataReferenceForProjectReference(ProjectReference projectReference, params string?[] possibleMetadataReferencePaths)
- {
- foreach (var path in possibleMetadataReferencePaths)
- {
- if (path != null)
- {
- Remove(path);
- }
- }
+ public void SwapMetadataReferenceForProjectReference(ProjectReference projectReference, params string?[] possibleMetadataReferencePaths)
+ {
+ foreach (var path in possibleMetadataReferencePaths)
+ {
+ if (path != null)
+ {
+ Remove(path);
+ }
+ }
- AddProjectReference(projectReference);
- }
+ AddProjectReference(projectReference);
+ }
- ///
- /// Returns true if a metadata reference with the given file path is contained within this list.
- ///
- public bool Contains(string? filePath)
- => filePath != null
- && _pathToIndicesMap.ContainsKey(filePath);
+ ///
+ /// Returns true if a metadata reference with the given file path is contained within this list.
+ ///
+ public bool Contains(string? filePath)
+ => filePath != null
+ && _pathToIndicesMap.ContainsKey(filePath);
- ///
- /// Removes the metadata reference with the given file path from this list.
- ///
- public void Remove(string filePath)
- {
- if (filePath != null && _pathToIndicesMap.TryGetValue(filePath, out var indices))
- {
- _indicesToRemove.AddRange(indices);
- }
- }
+ ///
+ /// Removes the metadata reference with the given file path from this list.
+ ///
+ public void Remove(string filePath)
+ {
+ if (filePath != null && _pathToIndicesMap.TryGetValue(filePath, out var indices))
+ {
+ _indicesToRemove.AddRange(indices);
+ }
+ }
- public ProjectInfo? SelectProjectInfoByOutput(IEnumerable projectInfos)
- {
- foreach (var projectInfo in projectInfos)
- {
- var outputFilePath = projectInfo.OutputFilePath;
- var outputRefFilePath = projectInfo.OutputRefFilePath;
- if (outputFilePath != null &&
- outputRefFilePath != null &&
- (Contains(outputFilePath) || Contains(outputRefFilePath)))
- {
- return projectInfo;
- }
- }
+ public ProjectInfo? SelectProjectInfoByOutput(IEnumerable projectInfos)
+ {
+ foreach (var projectInfo in projectInfos)
+ {
+ var outputFilePath = projectInfo.OutputFilePath;
+ var outputRefFilePath = projectInfo.OutputRefFilePath;
+ if (outputFilePath != null &&
+ outputRefFilePath != null &&
+ (Contains(outputFilePath) || Contains(outputRefFilePath)))
+ {
+ return projectInfo;
+ }
+ }
- return null;
- }
+ return null;
+ }
- public ImmutableArray GetUnresolvedMetadataReferences()
- {
- var builder = ImmutableArray.CreateBuilder();
+ public ImmutableArray GetUnresolvedMetadataReferences()
+ {
+ var builder = ImmutableArray.CreateBuilder();
- foreach (var metadataReference in GetMetadataReferences())
- {
- if (metadataReference is UnresolvedMetadataReference unresolvedMetadataReference)
- {
- builder.Add(unresolvedMetadataReference);
- }
- }
+ foreach (var metadataReference in GetMetadataReferences())
+ {
+ if (metadataReference is UnresolvedMetadataReference unresolvedMetadataReference)
+ {
+ builder.Add(unresolvedMetadataReference);
+ }
+ }
- return builder.ToImmutableAndClear();
- }
+ return builder.ToImmutableAndClear();
+ }
- private ImmutableArray GetMetadataReferences()
- {
- var builder = ImmutableArray.CreateBuilder();
+ private ImmutableArray GetMetadataReferences()
+ {
+ var builder = ImmutableArray.CreateBuilder();
- // used to eliminate duplicates
- var _ = PooledHashSet.GetInstance(out var set);
+ // used to eliminate duplicates
+ var _ = PooledHashSet.GetInstance(out var set);
- for (var index = 0; index < _metadataReferences.Length; index++)
- {
- var reference = _metadataReferences[index];
- if (!_indicesToRemove.Contains(index) && set.Add(reference))
- {
- builder.Add(reference);
- }
- }
+ for (var index = 0; index < _metadataReferences.Length; index++)
+ {
+ var reference = _metadataReferences[index];
+ if (!_indicesToRemove.Contains(index) && set.Add(reference))
+ {
+ builder.Add(reference);
+ }
+ }
- return builder.ToImmutableAndClear();
- }
+ return builder.ToImmutableAndClear();
+ }
- private ImmutableHashSet GetProjectReferences()
- => _projectReferences.ToImmutable();
+ private ImmutableHashSet GetProjectReferences()
+ => _projectReferences.ToImmutable();
- public ResolvedReferences ToResolvedReferences()
- => new(GetProjectReferences(), GetMetadataReferences());
- }
+ public ResolvedReferences ToResolvedReferences()
+ => new(GetProjectReferences(), GetMetadataReferences());
+ }
- private async Task ResolveReferencesAsync(ProjectId id, ProjectFileInfo projectFileInfo, CommandLineArguments commandLineArgs, CancellationToken cancellationToken)
- {
- // First, gather all of the metadata references from the command-line arguments.
- var resolvedMetadataReferences = commandLineArgs.ResolveMetadataReferences(
- new WorkspaceMetadataFileReferenceResolver(
- metadataService: _solutionServices.GetRequiredService(),
- pathResolver: new RelativePathResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory)));
+ private async Task ResolveReferencesAsync(ProjectId id, ProjectFileInfo projectFileInfo, CommandLineArguments commandLineArgs, CancellationToken cancellationToken)
+ {
+ // First, gather all of the metadata references from the command-line arguments.
+ var resolvedMetadataReferences = commandLineArgs.ResolveMetadataReferences(
+ new WorkspaceMetadataFileReferenceResolver(
+ metadataService: _solutionServices.GetRequiredService(),
+ pathResolver: new RelativePathResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory)));
- var builder = new ResolvedReferencesBuilder(resolvedMetadataReferences);
+ var builder = new ResolvedReferencesBuilder(resolvedMetadataReferences);
- var projectDirectory = Path.GetDirectoryName(projectFileInfo.FilePath);
- RoslynDebug.AssertNotNull(projectDirectory);
+ var projectDirectory = Path.GetDirectoryName(projectFileInfo.FilePath);
+ RoslynDebug.AssertNotNull(projectDirectory);
- // Next, iterate through all project references in the file and create project references.
- foreach (var projectFileReference in projectFileInfo.ProjectReferences)
- {
- var aliases = projectFileReference.Aliases;
+ // Next, iterate through all project references in the file and create project references.
+ foreach (var projectFileReference in projectFileInfo.ProjectReferences)
+ {
+ var aliases = projectFileReference.Aliases;
- if (_pathResolver.TryGetAbsoluteProjectPath(projectFileReference.Path, baseDirectory: projectDirectory, _discoveredProjectOptions.OnPathFailure, out var projectReferencePath))
- {
- // The easiest case is to add a reference to a project we already know about.
- if (TryAddReferenceToKnownProject(id, projectReferencePath, aliases, builder))
- {
- continue;
- }
+ if (_pathResolver.TryGetAbsoluteProjectPath(projectFileReference.Path, baseDirectory: projectDirectory, _discoveredProjectOptions.OnPathFailure, out var projectReferencePath))
+ {
+ // The easiest case is to add a reference to a project we already know about.
+ if (TryAddReferenceToKnownProject(id, projectReferencePath, aliases, builder))
+ {
+ continue;
+ }
- if (projectFileReference.ReferenceOutputAssembly)
- {
- // If we don't know how to load a project (that is, it's not a language we support), we can still
- // attempt to verify that its output exists on disk and is included in our set of metadata references.
- // If it is, we'll just leave it in place.
- if (!IsProjectLoadable(projectReferencePath) &&
- await VerifyUnloadableProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
- {
- continue;
- }
+ if (projectFileReference.ReferenceOutputAssembly)
+ {
+ // If we don't know how to load a project (that is, it's not a language we support), we can still
+ // attempt to verify that its output exists on disk and is included in our set of metadata references.
+ // If it is, we'll just leave it in place.
+ if (!IsProjectLoadable(projectReferencePath) &&
+ await VerifyUnloadableProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
+ {
+ continue;
+ }
- // If metadata is preferred, see if the project reference's output exists on disk and is included
- // in our metadata references. If it is, don't create a project reference; we'll just use the metadata.
- if (_preferMetadataForReferencesOfDiscoveredProjects &&
- await VerifyProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
- {
- continue;
- }
+ // If metadata is preferred, see if the project reference's output exists on disk and is included
+ // in our metadata references. If it is, don't create a project reference; we'll just use the metadata.
+ if (_preferMetadataForReferencesOfDiscoveredProjects &&
+ await VerifyProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
+ {
+ continue;
+ }
- // Finally, we'll try to load and reference the project.
- if (await TryLoadAndAddReferenceAsync(id, projectReferencePath, aliases, builder, cancellationToken).ConfigureAwait(false))
- {
- continue;
- }
- }
- else
- {
- // Load the project but do not add a reference:
- _ = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);
- continue;
- }
- }
+ // Finally, we'll try to load and reference the project.
+ if (await TryLoadAndAddReferenceAsync(id, projectReferencePath, aliases, builder, cancellationToken).ConfigureAwait(false))
+ {
+ continue;
+ }
+ }
+ else
+ {
+ // Load the project but do not add a reference:
+ _ = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);
+ continue;
+ }
+ }
- // We weren't able to handle this project reference, so add it without further processing.
- var unknownProjectId = _projectMap.GetOrCreateProjectId(projectFileReference.Path);
- var newProjectReference = CreateProjectReference(from: id, to: unknownProjectId, aliases);
- builder.AddProjectReference(newProjectReference);
- }
+ // We weren't able to handle this project reference, so add it without further processing.
+ var unknownProjectId = _projectMap.GetOrCreateProjectId(projectFileReference.Path);
+ var newProjectReference = CreateProjectReference(from: id, to: unknownProjectId, aliases);
+ builder.AddProjectReference(newProjectReference);
+ }
- // Are there still any unresolved metadata references? If so, remove them and report diagnostics.
- foreach (var unresolvedMetadataReference in builder.GetUnresolvedMetadataReferences())
- {
- var filePath = unresolvedMetadataReference.Reference;
+ // Are there still any unresolved metadata references? If so, remove them and report diagnostics.
+ foreach (var unresolvedMetadataReference in builder.GetUnresolvedMetadataReferences())
+ {
+ var filePath = unresolvedMetadataReference.Reference;
- builder.Remove(filePath);
+ builder.Remove(filePath);
- _diagnosticReporter.Report(new ProjectDiagnostic(
- WorkspaceDiagnosticKind.Warning,
- string.Format(WorkspaceMSBuildResources.Unresolved_metadata_reference_removed_from_project_0, filePath),
- id));
- }
+ _diagnosticReporter.Report(new ProjectDiagnostic(
+ WorkspaceDiagnosticKind.Warning,
+ string.Format(WorkspaceMSBuildResources.Unresolved_metadata_reference_removed_from_project_0, filePath),
+ id));
+ }
- return builder.ToResolvedReferences();
- }
+ return builder.ToResolvedReferences();
+ }
- private async Task TryLoadAndAddReferenceAsync(ProjectId id, string projectReferencePath, ImmutableArray aliases, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
- {
- var projectReferenceInfos = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);
+ private async Task TryLoadAndAddReferenceAsync(ProjectId id, string projectReferencePath, ImmutableArray aliases, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
+ {
+ var projectReferenceInfos = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);
- if (projectReferenceInfos.IsEmpty)
- {
- return false;
- }
+ if (projectReferenceInfos.IsEmpty)
+ {
+ return false;
+ }
- // Find the project reference info whose output we have a metadata reference for.
- ProjectInfo? projectReferenceInfo = null;
- foreach (var info in projectReferenceInfos)
- {
- var outputFilePath = info.OutputFilePath;
- var outputRefFilePath = info.OutputRefFilePath;
- if (outputFilePath != null &&
- outputRefFilePath != null &&
- (builder.Contains(outputFilePath) || builder.Contains(outputRefFilePath)))
- {
- projectReferenceInfo = info;
- break;
- }
- }
+ // Find the project reference info whose output we have a metadata reference for.
+ ProjectInfo? projectReferenceInfo = null;
+ foreach (var info in projectReferenceInfos)
+ {
+ var outputFilePath = info.OutputFilePath;
+ var outputRefFilePath = info.OutputRefFilePath;
+ if (outputFilePath != null &&
+ outputRefFilePath != null &&
+ (builder.Contains(outputFilePath) || builder.Contains(outputRefFilePath)))
+ {
+ projectReferenceInfo = info;
+ break;
+ }
+ }
- if (projectReferenceInfo is null)
- {
- // We didn't find the project reference info that matches any of our metadata references.
- // In this case, we'll go ahead and use the first project reference info that was found,
- // but report a warning because this likely means that either a metadata reference path
- // or a project output path is incorrect.
+ if (projectReferenceInfo is null)
+ {
+ // We didn't find the project reference info that matches any of our metadata references.
+ // In this case, we'll go ahead and use the first project reference info that was found,
+ // but report a warning because this likely means that either a metadata reference path
+ // or a project output path is incorrect.
- projectReferenceInfo = projectReferenceInfos[0];
+ projectReferenceInfo = projectReferenceInfos[0];
- _diagnosticReporter.Report(new ProjectDiagnostic(
- WorkspaceDiagnosticKind.Warning,
- string.Format(WorkspaceMSBuildResources.Found_project_reference_without_a_matching_metadata_reference_0, projectReferencePath),
- id));
- }
+ _diagnosticReporter.Report(new ProjectDiagnostic(
+ WorkspaceDiagnosticKind.Warning,
+ string.Format(WorkspaceMSBuildResources.Found_project_reference_without_a_matching_metadata_reference_0, projectReferencePath),
+ id));
+ }
- if (!ProjectReferenceExists(to: id, from: projectReferenceInfo))
- {
- var newProjectReference = CreateProjectReference(from: id, to: projectReferenceInfo.Id, aliases);
- builder.SwapMetadataReferenceForProjectReference(newProjectReference, projectReferenceInfo.OutputRefFilePath, projectReferenceInfo.OutputFilePath);
- }
- else
- {
- // This project already has a reference on us. Don't introduce a circularity by referencing it.
- // However, if the project's output doesn't exist on disk, we need to remove from our list of
- // metadata references to avoid failures later. Essentially, the concern here is that the metadata
- // reference is an UnresolvedMetadataReference, which will throw when we try to create a
- // Compilation with it.
+ if (!ProjectReferenceExists(to: id, from: projectReferenceInfo))
+ {
+ var newProjectReference = CreateProjectReference(from: id, to: projectReferenceInfo.Id, aliases);
+ builder.SwapMetadataReferenceForProjectReference(newProjectReference, projectReferenceInfo.OutputRefFilePath, projectReferenceInfo.OutputFilePath);
+ }
+ else
+ {
+ // This project already has a reference on us. Don't introduce a circularity by referencing it.
+ // However, if the project's output doesn't exist on disk, we need to remove from our list of
+ // metadata references to avoid failures later. Essentially, the concern here is that the metadata
+ // reference is an UnresolvedMetadataReference, which will throw when we try to create a
+ // Compilation with it.
- var outputRefFilePath = projectReferenceInfo.OutputRefFilePath;
- if (outputRefFilePath != null && !File.Exists(outputRefFilePath))
- {
- builder.Remove(outputRefFilePath);
- }
+ var outputRefFilePath = projectReferenceInfo.OutputRefFilePath;
+ if (outputRefFilePath != null && !File.Exists(outputRefFilePath))
+ {
+ builder.Remove(outputRefFilePath);
+ }
- var outputFilePath = projectReferenceInfo.OutputFilePath;
- if (outputFilePath != null && !File.Exists(outputFilePath))
- {
- builder.Remove(outputFilePath);
- }
- }
+ var outputFilePath = projectReferenceInfo.OutputFilePath;
+ if (outputFilePath != null && !File.Exists(outputFilePath))
+ {
+ builder.Remove(outputFilePath);
+ }
+ }
- // Note that we return true even if we don't actually add a reference due to a circularity because,
- // in that case, we've still handled everything.
- return true;
- }
+ // Note that we return true even if we don't actually add a reference due to a circularity because,
+ // in that case, we've still handled everything.
+ return true;
+ }
- private bool IsProjectLoadable(string projectPath)
- => _projectFileExtensionRegistry.TryGetLanguageNameFromProjectPath(projectPath, DiagnosticReportingMode.Ignore, out _);
+ private bool IsProjectLoadable(string projectPath)
+ => _projectFileExtensionRegistry.TryGetLanguageNameFromProjectPath(projectPath, DiagnosticReportingMode.Ignore, out _);
- private async Task VerifyUnloadableProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
- {
- var buildHost = await _buildHostProcessManager.GetBuildHostWithFallbackAsync(projectPath, cancellationToken).ConfigureAwait(false);
- var outputFilePath = await buildHost.TryGetProjectOutputPathAsync(projectPath, cancellationToken).ConfigureAwait(false);
- return outputFilePath != null
- && builder.Contains(outputFilePath)
- && File.Exists(outputFilePath);
- }
+ private async Task VerifyUnloadableProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
+ {
+ var buildHost = await _buildHostProcessManager.GetBuildHostWithFallbackAsync(projectPath, cancellationToken).ConfigureAwait(false);
+ var outputFilePath = await buildHost.TryGetProjectOutputPathAsync(projectPath, cancellationToken).ConfigureAwait(false);
+ return outputFilePath != null
+ && builder.Contains(outputFilePath)
+ && File.Exists(outputFilePath);
+ }
- private async Task VerifyProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
- {
- // Note: Load the project, but don't report failures.
- var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, DiagnosticReportingOptions.IgnoreAll, cancellationToken).ConfigureAwait(false);
+ private async Task VerifyProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
+ {
+ // Note: Load the project, but don't report failures.
+ var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, DiagnosticReportingOptions.IgnoreAll, cancellationToken).ConfigureAwait(false);
- foreach (var projectFileInfo in projectFileInfos)
- {
- var outputFilePath = projectFileInfo.OutputFilePath;
- var outputRefFilePath = projectFileInfo.OutputRefFilePath;
+ foreach (var projectFileInfo in projectFileInfos)
+ {
+ var outputFilePath = projectFileInfo.OutputFilePath;
+ var outputRefFilePath = projectFileInfo.OutputRefFilePath;
- if ((builder.Contains(outputFilePath) && File.Exists(outputFilePath)) ||
- (builder.Contains(outputRefFilePath) && File.Exists(outputRefFilePath)))
- {
- return true;
- }
- }
+ if ((builder.Contains(outputFilePath) && File.Exists(outputFilePath)) ||
+ (builder.Contains(outputRefFilePath) && File.Exists(outputRefFilePath)))
+ {
+ return true;
+ }
+ }
- return false;
- }
+ return false;
+ }
- private ProjectReference CreateProjectReference(ProjectId from, ProjectId to, ImmutableArray aliases)
- {
- var newReference = new ProjectReference(to, aliases);
- _projectIdToProjectReferencesMap.MultiAdd(from, newReference);
- return newReference;
- }
+ private ProjectReference CreateProjectReference(ProjectId from, ProjectId to, ImmutableArray aliases)
+ {
+ var newReference = new ProjectReference(to, aliases);
+ _projectIdToProjectReferencesMap.MultiAdd(from, newReference);
+ return newReference;
+ }
- private bool ProjectReferenceExists(ProjectId to, ProjectId from)
- => _projectIdToProjectReferencesMap.TryGetValue(from, out var references)
- && references.Any(pr => pr.ProjectId == to);
+ private bool ProjectReferenceExists(ProjectId to, ProjectId from)
+ => _projectIdToProjectReferencesMap.TryGetValue(from, out var references)
+ && references.Any(pr => pr.ProjectId == to);
- private static bool ProjectReferenceExists(ProjectId to, ProjectInfo from)
- => from.ProjectReferences.Any(pr => pr.ProjectId == to);
+ private static bool ProjectReferenceExists(ProjectId to, ProjectInfo from)
+ => from.ProjectReferences.Any(pr => pr.ProjectId == to);
- private bool TryAddReferenceToKnownProject(
- ProjectId id,
- string projectReferencePath,
- ImmutableArray aliases,
- ResolvedReferencesBuilder builder)
- {
- if (_projectMap.TryGetIdsByProjectPath(projectReferencePath, out var projectReferenceIds))
- {
- foreach (var projectReferenceId in projectReferenceIds)
- {
- // Don't add a reference if the project already has a reference on us. Otherwise, it will cause a circularity.
- if (ProjectReferenceExists(to: id, from: projectReferenceId))
- {
- return false;
- }
+ private bool TryAddReferenceToKnownProject(
+ ProjectId id,
+ string projectReferencePath,
+ ImmutableArray aliases,
+ ResolvedReferencesBuilder builder)
+ {
+ if (_projectMap.TryGetIdsByProjectPath(projectReferencePath, out var projectReferenceIds))
+ {
+ foreach (var projectReferenceId in projectReferenceIds)
+ {
+ // Don't add a reference if the project already has a reference on us. Otherwise, it will cause a circularity.
+ if (ProjectReferenceExists(to: id, from: projectReferenceId))
+ {
+ return false;
+ }
- var outputRefFilePath = _projectMap.GetOutputRefFilePathById(projectReferenceId);
- var outputFilePath = _projectMap.GetOutputFilePathById(projectReferenceId);
+ var outputRefFilePath = _projectMap.GetOutputRefFilePathById(projectReferenceId);
+ var outputFilePath = _projectMap.GetOutputFilePathById(projectReferenceId);
- if (builder.Contains(outputRefFilePath) ||
- builder.Contains(outputFilePath))
- {
- var newProjectReference = CreateProjectReference(from: id, to: projectReferenceId, aliases);
- builder.SwapMetadataReferenceForProjectReference(newProjectReference, outputRefFilePath, outputFilePath);
- return true;
- }
- }
- }
+ if (builder.Contains(outputRefFilePath) ||
+ builder.Contains(outputFilePath))
+ {
+ var newProjectReference = CreateProjectReference(from: id, to: projectReferenceId, aliases);
+ builder.SwapMetadataReferenceForProjectReference(newProjectReference, outputRefFilePath, outputFilePath);
+ return true;
+ }
+ }
+ }
- return false;
- }
- }
+ return false;
+ }
+ }
}
diff --git a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.cs b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.cs
index 0b22dc4..8dadef8 100644
--- a/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.cs
+++ b/src/SharpIDE.Application/Features/Analysis/ProjectLoader/CustomMsBuildProjectLoader.cs
@@ -56,68 +56,68 @@ public partial class CustomMsBuildProjectLoader(Workspace workspace, ImmutableDi
}
///
- /// Loads the for the specified solution file, including all projects referenced by the solution file and
- /// all the projects referenced by the project files.
- ///
- /// The path to the solution file to be loaded. This may be an absolute path or a path relative to the
- /// current working directory.
- /// An optional that will receive updates as the solution is loaded.
- /// An optional that will log MSBuild results.
- /// An optional to allow cancellation of this operation.
- public new async Task<(SolutionInfo, Dictionary)> LoadSolutionInfoAsync(
- string solutionFilePath,
- IProgress? progress = null,
- ILogger? msbuildLogger = null,
- CancellationToken cancellationToken = default)
- {
- if (solutionFilePath == null)
- {
- throw new ArgumentNullException(nameof(solutionFilePath));
- }
+ /// Loads the for the specified solution file, including all projects referenced by the solution file and
+ /// all the projects referenced by the project files.
+ ///
+ /// The path to the solution file to be loaded. This may be an absolute path or a path relative to the
+ /// current working directory.
+ /// An optional that will receive updates as the solution is loaded.
+ /// An optional that will log MSBuild results.
+ /// An optional to allow cancellation of this operation.
+ public new async Task<(SolutionInfo, Dictionary)> LoadSolutionInfoAsync(
+ string solutionFilePath,
+ IProgress? progress = null,
+ ILogger? msbuildLogger = null,
+ CancellationToken cancellationToken = default)
+ {
+ if (solutionFilePath == null)
+ {
+ throw new ArgumentNullException(nameof(solutionFilePath));
+ }
- var reportingMode = GetReportingModeForUnrecognizedProjects();
+ var reportingMode = GetReportingModeForUnrecognizedProjects();
- var reportingOptions = new DiagnosticReportingOptions(
- onPathFailure: reportingMode,
- onLoaderFailure: reportingMode);
+ var reportingOptions = new DiagnosticReportingOptions(
+ onPathFailure: reportingMode,
+ onLoaderFailure: reportingMode);
- var (absoluteSolutionPath, projects) = await SolutionFileReader.ReadSolutionFileAsync(solutionFilePath, _pathResolver, reportingMode, cancellationToken).ConfigureAwait(false);
- var projectPaths = projects.SelectAsArray(p => p.ProjectPath);
+ var (absoluteSolutionPath, projects) = await SolutionFileReader.ReadSolutionFileAsync(solutionFilePath, _pathResolver, reportingMode, cancellationToken).ConfigureAwait(false);
+ var projectPaths = projects.SelectAsArray(p => p.ProjectPath);
- using (_dataGuard.DisposableWait(cancellationToken))
- {
- SetSolutionProperties(absoluteSolutionPath);
- }
+ using (_dataGuard.DisposableWait(cancellationToken))
+ {
+ SetSolutionProperties(absoluteSolutionPath);
+ }
- IBinLogPathProvider binLogPathProvider = null!; // TODO: Fix
+ IBinLogPathProvider binLogPathProvider = null!; // TODO: Fix
- var buildHostProcessManager = new BuildHostProcessManager(Properties, binLogPathProvider, _loggerFactory);
- await using var _ = buildHostProcessManager.ConfigureAwait(false);
+ var buildHostProcessManager = new BuildHostProcessManager(Properties, binLogPathProvider, _loggerFactory);
+ await using var _ = buildHostProcessManager.ConfigureAwait(false);
- var worker = new CustomWorker(
- _solutionServices,
- _diagnosticReporter,
- _pathResolver,
- _projectFileExtensionRegistry,
- buildHostProcessManager,
- projectPaths,
- // TryGetAbsoluteSolutionPath should not return an invalid path
- baseDirectory: Path.GetDirectoryName(absoluteSolutionPath)!,
- projectMap: null,
- progress,
- requestedProjectOptions: reportingOptions,
- discoveredProjectOptions: reportingOptions,
- preferMetadataForReferencesOfDiscoveredProjects: false);
+ var worker = new CustomWorker(
+ _solutionServices,
+ _diagnosticReporter,
+ _pathResolver,
+ _projectFileExtensionRegistry,
+ buildHostProcessManager,
+ projectPaths,
+ // TryGetAbsoluteSolutionPath should not return an invalid path
+ baseDirectory: Path.GetDirectoryName(absoluteSolutionPath)!,
+ projectMap: null,
+ progress,
+ requestedProjectOptions: reportingOptions,
+ discoveredProjectOptions: reportingOptions,
+ preferMetadataForReferencesOfDiscoveredProjects: false);
- var (projectInfos, projectFileInfos) = await worker.LoadAsync(cancellationToken).ConfigureAwait(false);
+ var (projectInfos, projectFileInfos) = await worker.LoadAsync(cancellationToken).ConfigureAwait(false);
- // construct workspace from loaded project infos
- var solutionInfo = SolutionInfo.Create(
- SolutionId.CreateNewId(debugName: absoluteSolutionPath),
- version: default,
- absoluteSolutionPath,
- projectInfos);
+ // construct workspace from loaded project infos
+ var solutionInfo = SolutionInfo.Create(
+ SolutionId.CreateNewId(debugName: absoluteSolutionPath),
+ version: default,
+ absoluteSolutionPath,
+ projectInfos);
- return (solutionInfo, projectFileInfos);
- }
+ return (solutionInfo, projectFileInfos);
+ }
}