File: MetadataAsSource\MetadataAsSourceHelpers.cs
Web Access
Project: src\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.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.MetadataAsSource;
 
/// <summary>
/// Helpers shared by both the text service and the editor service
/// </summary>
internal sealed class MetadataAsSourceHelpers
{
 
#if false
    public static void ValidateSymbolArgument(ISymbol symbol, string parameterName)
    {
        if (symbol == null)
        {
            throw new ArgumentNullException(parameterName);
        }
        else if (!MetadataAsSourceHelpers.ValidSymbolKinds.Contains(symbol.Kind))
        {
            throw new ArgumentException(FeaturesResources.generating_source_for_symbols_of_this_type_is_not_supported, parameterName);
        }
    }
#endif
 
    public static string GetAssemblyInfo(IAssemblySymbol assemblySymbol)
    {
        return string.Format(
            "{0} {1}",
            FeaturesResources.Assembly,
            assemblySymbol.Identity.GetDisplayName());
    }
 
    public static string GetAssemblyDisplay(Compilation compilation, IAssemblySymbol assemblySymbol)
    {
        // This method is only used to generate a comment at the top of Metadata-as-Source documents and
        // previous submissions are never viewed as metadata (i.e. we always have compilations) so there's no
        // need to consume compilation.ScriptCompilationInfo.PreviousScriptCompilation.
        var assemblyReference = compilation.GetMetadataReference(assemblySymbol);
        return assemblyReference?.Display ?? FeaturesResources.location_unknown;
    }
 
    public static INamedTypeSymbol GetTopLevelContainingNamedType(ISymbol symbol)
        => TryGetTopLevelContainingNamedType(symbol) ?? throw ExceptionUtilities.UnexpectedValue(symbol);
 
    public static INamedTypeSymbol? TryGetTopLevelContainingNamedType(ISymbol symbol)
    {
        // Traverse up until we find a named type that is parented by the namespace
        var topLevelNamedType = symbol;
        while (topLevelNamedType.ContainingSymbol != symbol.ContainingNamespace ||
            topLevelNamedType.Kind != SymbolKind.NamedType)
        {
            topLevelNamedType = topLevelNamedType.ContainingSymbol;
            if (topLevelNamedType == null)
            {
                return null;
            }
        }
 
        return (INamedTypeSymbol)topLevelNamedType;
    }
 
    public static async Task<Location> GetLocationInGeneratedSourceAsync(SymbolKey symbolId, Document generatedDocument, CancellationToken cancellationToken)
    {
        var resolution = symbolId.Resolve(
            await generatedDocument.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false),
            ignoreAssemblyKey: true, cancellationToken: cancellationToken);
 
        var location = GetFirstSourceLocation(resolution);
        if (location == null)
        {
            // If we cannot find the location of the  symbol.  Just put the caret at the 
            // beginning of the file.
            var tree = await generatedDocument.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
            location = Location.Create(tree, new TextSpan(0, 0));
        }
 
        return location;
    }
 
    private static Location? GetFirstSourceLocation(SymbolKeyResolution resolution)
    {
        foreach (var symbol in resolution)
        {
            foreach (var location in symbol.Locations)
            {
                if (location.IsInSource)
                {
                    return location;
                }
            }
        }
 
        return null;
    }
 
    public static bool IsReferenceAssembly(IAssemblySymbol assemblySymbol)
    {
        foreach (var attribute in assemblySymbol.GetAttributes())
        {
            if (attribute.AttributeClass?.Name == nameof(ReferenceAssemblyAttribute) &&
                attribute.AttributeClass.ToNameDisplayString() == typeof(ReferenceAssemblyAttribute).FullName)
            {
                return true;
            }
        }
 
        return false;
    }
}