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