| File: Language\Components\TypeNameHelper.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language.CodeGeneration; namespace Microsoft.AspNetCore.Razor.Language; internal static partial class TypeNameHelper { private const string GlobalPrefix = "global::"; private static readonly ImmutableHashSet<ReadOnlyMemory<char>> PredefinedTypeNames = new[] { "bool".AsMemory(), "int".AsMemory(), "string".AsMemory(), "float".AsMemory(), "double".AsMemory(), "decimal".AsMemory(), "byte".AsMemory(), "short".AsMemory(), "long".AsMemory(), "char".AsMemory(), "object".AsMemory(), "dynamic".AsMemory(), "uint".AsMemory(), "ushort".AsMemory(), "ulong".AsMemory(), "sbyte".AsMemory(), "nint".AsMemory(), "nuint".AsMemory(), }.ToImmutableHashSet(NameComparer.Instance); internal static string GetGloballyQualifiedNameIfNeeded(string typeName) { if (typeName.Length == 0) { return typeName; } if (typeName.StartsWith(GlobalPrefix, StringComparison.Ordinal)) { return typeName; } // Mitigation for https://github.com/dotnet/razor-compiler/issues/332. When we add a reference to Roslyn // at this layer, we can do this property by using ParseTypeName and then rewriting the tree. For now, we // just skip prefixing tuples. if (typeName[0] == '(') { return typeName; } // Fast path, if the length doesn't fall within that of the // builtin c# types, then we can add global without further checks. if (typeName.Length is < 3 or > 7) { return GlobalPrefix + typeName; } if (PredefinedTypeNames.Contains(typeName.AsMemory())) { return typeName; } return GlobalPrefix + typeName; } public static void WriteGloballyQualifiedName(CodeWriter codeWriter, string typeName) { if (typeName == null) { throw new ArgumentNullException(nameof(typeName)); } WriteGloballyQualifiedName(codeWriter, typeName.AsMemory()); } internal static void WriteGloballyQualifiedName(CodeWriter codeWriter, ReadOnlyMemory<char> typeName) { WriteGlobalPrefixIfNeeded(codeWriter, typeName); codeWriter.Write(typeName); } /// <summary> /// Writes "global::" if the typename doesn't already start with it and isn't a predefined type. /// </summary> internal static void WriteGlobalPrefixIfNeeded(CodeWriter codeWriter, ReadOnlyMemory<char> typeName) { if (typeName.Length == 0) { return; } var typeNameSpan = typeName.Span; if (typeNameSpan.StartsWith(GlobalPrefix.AsSpan(), StringComparison.Ordinal)) { return; } // Mitigation for https://github.com/dotnet/razor-compiler/issues/332. When we add a reference to Roslyn // at this layer, we can do this property by using ParseTypeName and then rewriting the tree. For now, we // just skip prefixing tuples. if (typeNameSpan[0] == '(') { return; } // Fast path, if the length doesn't fall within that of the // builtin c# types, then we can add global without further checks. if (typeNameSpan.Length < 3 || typeNameSpan.Length > 7) { codeWriter.Write(GlobalPrefix); return; } if (PredefinedTypeNames.Contains(typeName)) { return; } codeWriter.Write(GlobalPrefix); } internal static ReadOnlyMemory<char> GetNonGenericTypeName(string typeName, out ReadOnlyMemory<char> genericTypeParameterList) { var memory = typeName.AsMemory(); var index = memory.Span.IndexOf('<'); genericTypeParameterList = index == -1 ? default : memory[index..]; return index == -1 ? memory : memory[..index]; } }