File: Workspaces\TestHostProject`1.cs
Web Access
Project: src\src\Workspaces\CoreTestUtilities\Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj (Microsoft.CodeAnalysis.Workspaces.Test.Utilities)
// 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.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Test.Utilities;
 
public abstract class TestHostProject<TDocument> : AbstractTestHostProject
    where TDocument : TestHostDocument
{
    private readonly HostLanguageServices _languageServices;
 
    private readonly ProjectId _id;
    private readonly string _name;
    private readonly IEnumerable<AnalyzerReference> _analyzerReferences;
    private readonly string _assemblyName;
    private readonly string _defaultNamespace;
 
    public IEnumerable<TDocument> Documents;
    public IEnumerable<TDocument> AdditionalDocuments;
    public IEnumerable<TDocument> AnalyzerConfigDocuments;
    public IEnumerable<ProjectReference> ProjectReferences;
 
    public override string Name
    {
        get
        {
            return _name;
        }
    }
 
    public IEnumerable<MetadataReference> MetadataReferences { get; }
 
    public IEnumerable<AnalyzerReference> AnalyzerReferences
    {
        get
        {
            return _analyzerReferences;
        }
    }
 
    public CompilationOptions CompilationOptions { get; }
 
    public ParseOptions ParseOptions { get; }
 
    public override ProjectId Id
    {
        get
        {
            return _id;
        }
    }
 
    public bool IsSubmission { get; }
 
    public override string AssemblyName
    {
        get
        {
            return _assemblyName;
        }
    }
 
    public Type HostObjectType { get; }
 
    public VersionStamp Version { get; }
 
    public string FilePath { get; private set; }
 
    internal void OnProjectFilePathChanged(string filePath)
        => FilePath = filePath;
 
    public string DefaultNamespace
    {
        get { return _defaultNamespace; }
    }
 
    protected TestHostProject(
        HostLanguageServices languageServices,
        CompilationOptions compilationOptions,
        ParseOptions parseOptions,
        string assemblyName,
        string projectName,
        IList<MetadataReference> references,
        IList<TDocument> documents,
        IList<TDocument> additionalDocuments = null,
        IList<TDocument> analyzerConfigDocuments = null,
        Type hostObjectType = null,
        bool isSubmission = false,
        string filePath = null,
        IList<AnalyzerReference> analyzerReferences = null,
        string defaultNamespace = null)
    {
        _assemblyName = assemblyName;
        _name = projectName;
        _id = ProjectId.CreateNewId(debugName: this.AssemblyName);
        _languageServices = languageServices;
        CompilationOptions = compilationOptions;
        ParseOptions = parseOptions;
        MetadataReferences = references;
        _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable<AnalyzerReference>();
        this.Documents = documents;
        this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable<TDocument>();
        this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable<TDocument>();
        ProjectReferences = SpecializedCollections.EmptyEnumerable<ProjectReference>();
        IsSubmission = isSubmission;
        HostObjectType = hostObjectType;
        Version = VersionStamp.Create();
        FilePath = filePath;
        _defaultNamespace = defaultNamespace;
    }
 
    protected TestHostProject(
        HostWorkspaceServices hostServices,
        string name = null,
        string language = null,
        CompilationOptions compilationOptions = null,
        ParseOptions parseOptions = null,
        IEnumerable<TDocument> documents = null,
        IEnumerable<TDocument> additionalDocuments = null,
        IEnumerable<TDocument> analyzerConfigDocuments = null,
        IEnumerable<TestHostProject<TDocument>> projectReferences = null,
        IEnumerable<MetadataReference> metadataReferences = null,
        IEnumerable<AnalyzerReference> analyzerReferences = null,
        string assemblyName = null,
        string defaultNamespace = null)
    {
        _name = name ?? "TestProject";
 
        _id = ProjectId.CreateNewId(debugName: this.Name);
 
        language = language ?? LanguageNames.CSharp;
        _languageServices = hostServices.GetLanguageServices(language);
 
        CompilationOptions = compilationOptions ?? this.LanguageServiceProvider.GetService<ICompilationFactoryService>().GetDefaultCompilationOptions();
        ParseOptions = parseOptions ?? this.LanguageServiceProvider.GetService<ISyntaxTreeFactoryService>().GetDefaultParseOptions();
        this.Documents = documents ?? SpecializedCollections.EmptyEnumerable<TDocument>();
        this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable<TDocument>();
        this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable<TDocument>();
        ProjectReferences = projectReferences != null ? projectReferences.Select(p => new ProjectReference(p.Id)) : SpecializedCollections.EmptyEnumerable<ProjectReference>();
        MetadataReferences = metadataReferences ?? new MetadataReference[] { NetFramework.mscorlib };
        _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable<AnalyzerReference>();
        _assemblyName = assemblyName ?? "TestProject";
        Version = VersionStamp.Create();
        _defaultNamespace = defaultNamespace;
 
        if (documents != null)
        {
            foreach (var doc in documents)
            {
                doc.SetProject(this);
            }
        }
 
        if (additionalDocuments != null)
        {
            foreach (var doc in additionalDocuments)
            {
                doc.SetProject(this);
            }
        }
 
        if (analyzerConfigDocuments != null)
        {
            foreach (var doc in analyzerConfigDocuments)
            {
                doc.SetProject(this);
            }
        }
    }
 
    internal void SetSolution()
    {
        // set up back pointer to this project.
        if (this.Documents != null)
        {
            foreach (var doc in this.Documents)
            {
                doc.SetProject(this);
            }
 
            foreach (var doc in this.AdditionalDocuments)
            {
                doc.SetProject(this);
            }
 
            foreach (var doc in this.AnalyzerConfigDocuments)
            {
                doc.SetProject(this);
            }
        }
    }
 
    internal void AddDocument(TDocument document)
    {
        this.Documents = this.Documents.Concat(new TDocument[] { document });
        document.SetProject(this);
    }
 
    internal void RemoveDocument(TDocument document)
        => this.Documents = this.Documents.Where(d => d != document);
 
    internal void AddAdditionalDocument(TDocument document)
    {
        this.AdditionalDocuments = this.AdditionalDocuments.Concat(new TDocument[] { document });
        document.SetProject(this);
    }
 
    internal void RemoveAdditionalDocument(TDocument document)
        => this.AdditionalDocuments = this.AdditionalDocuments.Where(d => d != document);
 
    internal void AddAnalyzerConfigDocument(TDocument document)
    {
        this.AnalyzerConfigDocuments = this.AnalyzerConfigDocuments.Concat(new TDocument[] { document });
        document.SetProject(this);
    }
 
    internal void RemoveAnalyzerConfigDocument(TDocument document)
        => this.AnalyzerConfigDocuments = this.AnalyzerConfigDocuments.Where(d => d != document);
 
    public override string Language
    {
        get
        {
            return _languageServices.Language;
        }
    }
 
    public override HostLanguageServices LanguageServiceProvider
    {
        get
        {
            return _languageServices;
        }
    }
 
    public ProjectInfo ToProjectInfo()
    {
        var info = ProjectInfo.Create(
            new ProjectInfo.ProjectAttributes(
                Id,
                Version,
                name: Name,
                assemblyName: AssemblyName,
                language: Language,
                compilationOutputInfo: default,
                checksumAlgorithm: Text.SourceHashAlgorithms.Default,
                defaultNamespace: DefaultNamespace,
                filePath: FilePath,
                outputFilePath: GetTestOutputFilePath(FilePath, "bin"),
                isSubmission: IsSubmission),
            CompilationOptions,
            ParseOptions,
            documents: Documents.Where(d => !d.IsSourceGenerated).Select(d => d.ToDocumentInfo()),
            ProjectReferences,
            MetadataReferences,
            AnalyzerReferences,
            additionalDocuments: AdditionalDocuments.Select(d => d.ToDocumentInfo()),
            analyzerConfigDocuments: AnalyzerConfigDocuments.Select(d => d.ToDocumentInfo()),
            HostObjectType);
 
        if (CompilationOptions != null)
        {
            info = info.WithCompilationOutputInfo(new CompilationOutputInfo(
                assemblyPath: GetTestOutputFilePath(FilePath, "obj"),
                generatedFilesOutputDirectory: null));
        }
 
        return info;
    }
 
    // It is identical with the internal extension method 'GetDefaultExtension' defined in OutputKind.cs.
    // However, we could not apply for InternalVisibleToTest due to other parts of this assembly
    // complaining about CS0507: "cannot change access modifiers when overriding 'access' inherited member".
    private static string GetDefaultExtension(OutputKind kind)
    {
        switch (kind)
        {
            case OutputKind.ConsoleApplication:
            case OutputKind.WindowsApplication:
            case OutputKind.WindowsRuntimeApplication:
                return ".exe";
 
            case OutputKind.DynamicallyLinkedLibrary:
                return ".dll";
 
            case OutputKind.NetModule:
                return ".netmodule";
 
            case OutputKind.WindowsRuntimeMetadata:
                return ".winmdobj";
 
            default:
                return ".dll";
        }
    }
 
    private string GetTestOutputFilePath(string projectFilePath, string subdir)
    {
        return CompilationOptions == null ? "" : Path.Combine(GetTestOutputDirectory(projectFilePath), subdir, AssemblyName + GetDefaultExtension(CompilationOptions.OutputKind));
    }
}