File: Workspace\Solution\CompilationOutputInfo.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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 Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis;
 
/// <summary>
/// Paths of files produced by the compilation.
/// </summary>
public readonly struct CompilationOutputInfo : IEquatable<CompilationOutputInfo>
{
    /// <summary>
    /// Full path to the assembly or module produced by the compilation, or <see langword="null"/> if unknown.
    /// </summary>
    public readonly string? AssemblyPath { get; }
 
    /// <summary>
    /// Absolute path to the root directory of source generated files, or null if it is not known.
    /// </summary>
    public readonly string? GeneratedFilesOutputDirectory { get; }
 
    // TODO: https://github.com/dotnet/roslyn/issues/35065
    // The project system doesn't currently provide paths to the PDB or XML files that the compiler produces.
    // public readonly string? PdbPath { get; }
    // public readonly string? DocumentationCommentsPath { get; }
 
    internal CompilationOutputInfo(string? assemblyPath, string? generatedFilesOutputDirectory)
    {
        AssemblyPath = assemblyPath;
        GeneratedFilesOutputDirectory = generatedFilesOutputDirectory;
    }
 
    public CompilationOutputInfo WithAssemblyPath(string? path)
        => new(assemblyPath: path, GeneratedFilesOutputDirectory);
 
    public CompilationOutputInfo WithGeneratedFilesOutputDirectory(string? path)
    {
        if (path != null && !PathUtilities.IsAbsolute(path))
        {
            throw new ArgumentException(WorkspacesResources.AbsolutePathExpected, nameof(path));
        }
 
        return new(AssemblyPath, path);
    }
 
    /// <summary>
    /// True if the project has an absolute generated source file output path.
    /// 
    /// Must be true for any workspace that supports EnC. If false, the compiler and IDE wouldn't agree on the file paths of source-generated files,
    /// which might cause different metadata to be emitted for file-scoped classes between compilation and EnC.
    /// </summary>
    internal bool HasEffectiveGeneratedFilesOutputDirectory
        => PathUtilities.IsAbsolute(GeneratedFilesOutputDirectory ?? AssemblyPath);
 
    /// <summary>
    /// Absolute path of a directory used to produce absolute file paths of source generated files.
    /// </summary>
    internal string? GetEffectiveGeneratedFilesOutputDirectory()
        => HasEffectiveGeneratedFilesOutputDirectory ? GeneratedFilesOutputDirectory ?? PathUtilities.GetDirectoryName(AssemblyPath) : null;
 
    public override bool Equals(object? obj)
        => obj is CompilationOutputInfo info && Equals(info);
 
    public bool Equals(CompilationOutputInfo other)
        => AssemblyPath == other.AssemblyPath &&
           GeneratedFilesOutputDirectory == other.GeneratedFilesOutputDirectory;
 
    public override int GetHashCode()
        => Hash.Combine(GeneratedFilesOutputDirectory, Hash.Combine(AssemblyPath, 0));
 
    public static bool operator ==(in CompilationOutputInfo left, in CompilationOutputInfo right)
        => left.Equals(right);
 
    public static bool operator !=(in CompilationOutputInfo left, in CompilationOutputInfo right)
        => !left.Equals(right);
 
    internal void WriteTo(ObjectWriter writer)
    {
        writer.WriteString(AssemblyPath);
        writer.WriteString(GeneratedFilesOutputDirectory);
    }
 
    internal static CompilationOutputInfo ReadFrom(ObjectReader reader)
    {
        var assemblyPath = reader.ReadString();
        var generatedFilesOutputDirectory = reader.ReadString();
        return new CompilationOutputInfo(assemblyPath, generatedFilesOutputDirectory);
    }
}