File: MetadataAsSource\MetadataAsSourceGeneratedFileInfo.cs
Web Access
Project: ..\..\..\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.IO;
using System.Text;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.MetadataAsSource
{
    internal sealed class MetadataAsSourceGeneratedFileInfo
    {
        public readonly ProjectId SourceProjectId;
        public readonly Workspace Workspace;
 
        public readonly AssemblyIdentity AssemblyIdentity;
        public readonly string LanguageName;
        public readonly bool SignaturesOnly;
        public readonly ImmutableArray<MetadataReference> References;
 
        public readonly string TemporaryFilePath;
 
        private readonly ParseOptions? _parseOptions;
 
        public MetadataAsSourceGeneratedFileInfo(string rootPath, Workspace sourceWorkspace, Project sourceProject, INamedTypeSymbol topLevelNamedType, bool signaturesOnly)
        {
            this.SourceProjectId = sourceProject.Id;
            this.Workspace = sourceWorkspace;
            this.LanguageName = signaturesOnly ? sourceProject.Language : LanguageNames.CSharp;
            this.SignaturesOnly = signaturesOnly;
 
            _parseOptions = sourceProject.Language == LanguageName
                ? sourceProject.ParseOptions
                : sourceProject.Solution.Services.GetLanguageServices(LanguageName).GetRequiredService<ISyntaxTreeFactoryService>().GetDefaultParseOptionsWithLatestLanguageVersion();
 
            this.References = sourceProject.MetadataReferences.ToImmutableArray();
            this.AssemblyIdentity = topLevelNamedType.ContainingAssembly.Identity;
 
            var extension = LanguageName == LanguageNames.CSharp ? ".cs" : ".vb";
 
            var directoryName = Guid.NewGuid().ToString("N");
            this.TemporaryFilePath = Path.Combine(rootPath, directoryName, topLevelNamedType.Name + extension);
        }
 
        public static Encoding Encoding => Encoding.UTF8;
        public static SourceHashAlgorithm ChecksumAlgorithm => SourceHashAlgorithms.Default;
 
        /// <summary>
        /// Creates a ProjectInfo to represent the fake project created for metadata as source documents.
        /// </summary>
        /// <param name="services">Solution services.</param>
        /// <param name="loadFileFromDisk">Whether the source file already exists on disk and should be included. If
        /// this is a false, a document is still created, but it's not backed by the file system and thus we won't
        /// try to load it.</param>
        public (ProjectInfo, DocumentId) GetProjectInfoAndDocumentId(SolutionServices services, bool loadFileFromDisk)
        {
            var projectId = ProjectId.CreateNewId();
 
            // Just say it's always a DLL since we probably won't have a Main method
            var compilationOptions = services.GetRequiredLanguageService<ICompilationFactoryService>(LanguageName).GetDefaultCompilationOptions().WithOutputKind(OutputKind.DynamicallyLinkedLibrary);
 
            var extension = LanguageName == LanguageNames.CSharp ? ".cs" : ".vb";
 
            // We need to include the version information of the assembly so InternalsVisibleTo and stuff works
            var assemblyInfoDocumentId = DocumentId.CreateNewId(projectId);
            var assemblyInfoFileName = "AssemblyInfo" + extension;
            var assemblyInfoString = LanguageName == LanguageNames.CSharp
                ? string.Format(@"[assembly: System.Reflection.AssemblyVersion(""{0}"")]", AssemblyIdentity.Version)
                : string.Format(@"<Assembly: System.Reflection.AssemblyVersion(""{0}"")>", AssemblyIdentity.Version);
 
            var assemblyInfoSourceText = SourceText.From(assemblyInfoString, Encoding, ChecksumAlgorithm);
 
            var assemblyInfoDocument = DocumentInfo.Create(
                assemblyInfoDocumentId,
                assemblyInfoFileName,
                loader: TextLoader.From(assemblyInfoSourceText.Container, VersionStamp.Default),
                filePath: null,
                isGenerated: true)
                .WithDesignTimeOnly(true);
 
            var generatedDocumentId = DocumentId.CreateNewId(projectId);
            var generatedDocument = DocumentInfo.Create(
                generatedDocumentId,
                Path.GetFileName(TemporaryFilePath),
                loader: loadFileFromDisk ? new WorkspaceFileTextLoader(services, TemporaryFilePath, Encoding) : null,
                filePath: TemporaryFilePath,
                isGenerated: true)
                .WithDesignTimeOnly(true);
 
            var projectInfo = ProjectInfo.Create(
                new ProjectInfo.ProjectAttributes(
                    id: projectId,
                    version: VersionStamp.Default,
                    name: AssemblyIdentity.Name,
                    assemblyName: AssemblyIdentity.Name,
                    language: LanguageName,
                    compilationOutputFilePaths: default,
                    checksumAlgorithm: ChecksumAlgorithm),
                compilationOptions: compilationOptions,
                parseOptions: _parseOptions,
                documents: new[] { assemblyInfoDocument, generatedDocument },
                metadataReferences: References);
 
            return (projectInfo, generatedDocumentId);
        }
    }
}