private async Task <ImmutableArray <ProjectFileInfo> > LoadProjectFileInfosAsync(
                string projectPath,
                DiagnosticReportingOptions reportingOptions,
                CancellationToken cancellationToken
                )
            {
                if (
                    !_projectFileLoaderRegistry.TryGetLoaderFromProjectPath(
                        projectPath,
                        reportingOptions.OnLoaderFailure,
                        out var loader
                        )
                    )
                {
                    return(ImmutableArray <ProjectFileInfo> .Empty); // Failure should already be reported.
                }

                var projectFile = await DoOperationAndReportProgressAsync(
                    ProjectLoadOperation.Evaluate,
                    projectPath,
                    targetFramework : null,
                    () =>
                    loader.LoadProjectFileAsync(
                        projectPath,
                        _buildManager,
                        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.
                if (projectFile.Log.HasFailure)
                {
                    _diagnosticReporter.Report(projectFile.Log);

                    return(ImmutableArray.Create(
                               ProjectFileInfo.CreateEmpty(loader.Language, projectPath, projectFile.Log)
                               ));
                }

                var projectFileInfos = await DoOperationAndReportProgressAsync(
                    ProjectLoadOperation.Build,
                    projectPath,
                    targetFramework : null,
                    () => projectFile.GetProjectFileInfosAsync(cancellationToken)
                    )
                                       .ConfigureAwait(false);

                var results = ImmutableArray.CreateBuilder <ProjectFileInfo>(
                    projectFileInfos.Length
                    );

                foreach (var projectFileInfo in projectFileInfos)
                {
                    // If any diagnostics were logged during build, we'll carry on and try to produce a meaningful project.
                    if (!projectFileInfo.Log.IsEmpty)
                    {
                        _diagnosticReporter.Report(projectFileInfo.Log);
                    }

                    results.Add(projectFileInfo);
                }

                return(results.MoveToImmutable());
            }
            private Task <ProjectInfo> 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 <ISyntaxTreeFactoryService>(language)
                                       ?.GetDefaultParseOptions();
                    var compilationOptions = GetLanguageService <ICompilationFactoryService>(
                        language
                        )
                                             ?.GetDefaultCompilationOptions();

                    return(Task.FromResult(
                               ProjectInfo.Create(
                                   projectId,
                                   version,
                                   projectName,
                                   assemblyName: assemblyName,
                                   language: language,
                                   filePath: projectPath,
                                   outputFilePath: string.Empty,
                                   outputRefFilePath: string.Empty,
                                   compilationOptions: compilationOptions,
                                   parseOptions: parseOptions,
                                   documents: SpecializedCollections.EmptyEnumerable <DocumentInfo>(),
                                   projectReferences: SpecializedCollections.EmptyEnumerable <ProjectReference>(),
                                   metadataReferences: SpecializedCollections.EmptyEnumerable <MetadataReference>(),
                                   analyzerReferences: SpecializedCollections.EmptyEnumerable <AnalyzerReference>(),
                                   additionalDocuments: SpecializedCollections.EmptyEnumerable <DocumentInfo>(),
                                   isSubmission: false,
                                   hostObjectType: null
                                   )
                               ));
                }

                return(DoOperationAndReportProgressAsync(
                           ProjectLoadOperation.Resolve,
                           projectPath,
                           projectFileInfo.TargetFramework,
                           async() =>
                {
                    var projectDirectory = Path.GetDirectoryName(projectPath);

                    // parse command line arguments
                    var commandLineParser = GetLanguageService <ICommandLineParserService>(
                        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 <IMetadataService>();
                    var compilationOptions = commandLineArgs.CompilationOptions
                                             .WithXmlReferenceResolver(new XmlFileResolver(projectDirectory))
                                             .WithSourceReferenceResolver(
                        new SourceFileResolver(
                            ImmutableArray <string> .Empty,
                            projectDirectory
                            )
                        )
                                             // TODO: https://github.com/dotnet/roslyn/issues/4967
                                             .WithMetadataReferenceResolver(
                        new WorkspaceMetadataFileReferenceResolver(
                            metadataService,
                            new RelativePathResolver(
                                ImmutableArray <string> .Empty,
                                projectDirectory
                                )
                            )
                        )
                                             .WithStrongNameProvider(
                        new DesktopStrongNameProvider(commandLineArgs.KeyFileSearchPaths)
                        )
                                             .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(
                        projectId,
                        version,
                        projectName,
                        assemblyName,
                        language,
                        projectPath,
                        outputFilePath: projectFileInfo.OutputFilePath,
                        outputRefFilePath: projectFileInfo.OutputRefFilePath,
                        compilationOptions: compilationOptions,
                        parseOptions: parseOptions,
                        documents: documents,
                        projectReferences: resolvedReferences.ProjectReferences,
                        metadataReferences: resolvedReferences.MetadataReferences,
                        analyzerReferences: analyzerReferences,
                        additionalDocuments: additionalDocuments,
                        isSubmission: false,
                        hostObjectType: null
                        )
                    .WithDefaultNamespace(projectFileInfo.DefaultNamespace)
                    .WithAnalyzerConfigDocuments(analyzerConfigDocuments)
                    .WithCompilationOutputInfo(
                        new CompilationOutputInfo(projectFileInfo.OutputFilePath)
                        );
                }
Beispiel #3
0
            private async Task <ResolvedReferences> 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: GetWorkspaceService <IMetadataService>(),
                        pathResolver: new RelativePathResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory)));

                var builder = new ResolvedReferencesBuilder(resolvedMetadataReferences);

                var projectDirectory = Path.GetDirectoryName(projectFileInfo.FilePath);

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

                        // Finally, we'll try to load and reference the project.
                        if (await TryLoadAndAddReferenceAsync(id, projectReferencePath, aliases, builder, 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);
                }

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

                    _diagnosticReporter.Report(new ProjectDiagnostic(
                                                   WorkspaceDiagnosticKind.Warning,
                                                   string.Format(WorkspaceMSBuildResources.Unresolved_metadata_reference_removed_from_project_0, filePath),
                                                   id));
                }

                return(builder.ToResolvedReferences());
            }