File: Symbols\FileIdentifier.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.CSharp;
 
internal sealed class FileIdentifier
{
    private class FileIdentifierData(string? encoderFallbackErrorMessage, string displayFilePath, ImmutableArray<byte> filePathChecksumOpt)
    {
        public readonly string? EncoderFallbackErrorMessage = encoderFallbackErrorMessage;
        public readonly string DisplayFilePath = displayFilePath;
        public readonly ImmutableArray<byte> FilePathChecksumOpt = filePathChecksumOpt;
    }
 
    private static readonly Encoding s_encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
 
    private readonly string _filePath;
    private FileIdentifierData? _data;
 
    private FileIdentifier(string filePath)
    {
        _filePath = filePath;
    }
 
    private FileIdentifier(ImmutableArray<byte> filePathChecksumOpt, string displayFilePath)
    {
        _data = new FileIdentifierData(encoderFallbackErrorMessage: null, displayFilePath, filePathChecksumOpt);
        _filePath = string.Empty;
    }
 
    [MemberNotNull(nameof(_data))]
    private void EnsureInitialized()
    {
        if (_data is null)
        {
            string? encoderFallbackErrorMessage = null;
            ImmutableArray<byte> hash = default;
            try
            {
                var encodedFilePath = s_encoding.GetBytes(_filePath);
                using var hashAlgorithm = SourceHashAlgorithms.CreateDefaultInstance();
                hash = hashAlgorithm.ComputeHash(encodedFilePath).ToImmutableArray();
            }
            catch (EncoderFallbackException ex)
            {
                encoderFallbackErrorMessage = ex.Message;
            }
 
            var displayFilePath = GeneratedNames.GetDisplayFilePath(_filePath);
 
            _data = new FileIdentifierData(encoderFallbackErrorMessage, displayFilePath, hash);
        }
    }
 
    public string DisplayFilePath
    {
        get
        {
            EnsureInitialized();
 
            return _data.DisplayFilePath;
        }
    }
 
    public string? EncoderFallbackErrorMessage
    {
        get
        {
            EnsureInitialized();
 
            return _data.EncoderFallbackErrorMessage;
        }
    }
 
    public ImmutableArray<byte> FilePathChecksumOpt
    {
        get
        {
            EnsureInitialized();
 
            return _data.FilePathChecksumOpt;
        }
    }
 
    public static FileIdentifier Create(SyntaxTree syntaxTree, SourceReferenceResolver? resolver)
        => new FileIdentifier(syntaxTree.GetNormalizedPath(resolver));
 
    public static FileIdentifier Create(string normalizedFilePath)
        => new FileIdentifier(normalizedFilePath);
 
    public static FileIdentifier Create(ImmutableArray<byte> filePathChecksumOpt, string displayFilePath)
        => new FileIdentifier(filePathChecksumOpt, displayFilePath);
}