diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/DocumentationSignatureGenerator.PartVisitor.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/DocumentationSignatureGenerator.PartVisitor.cs index 6f9815991ea194..5caa8cc8675454 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/DocumentationSignatureGenerator.PartVisitor.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/DocumentationSignatureGenerator.PartVisitor.cs @@ -8,8 +8,7 @@ namespace ILCompiler.Logging { - - public sealed partial class DocumentationSignatureGenerator + internal sealed partial class DocumentationSignatureGenerator { /// /// A visitor that generates the part of the documentation comment after the initial type diff --git a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/ILCompiler.Trimming.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/ILCompiler.Trimming.Tests.csproj index 935d178a29ef85..de47993ee6f56b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/ILCompiler.Trimming.Tests.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/ILCompiler.Trimming.Tests.csproj @@ -24,6 +24,14 @@ + + + + + + + + $(RuntimeBinDir) diff --git a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs index c312bddba0afa2..b2a6ea4cee9601 100644 --- a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs @@ -37,6 +37,7 @@ class LinkedMethodEntity : LinkedEntity } private readonly BaseAssemblyResolver originalsResolver; + private readonly TypeNameResolver originalsTypeNameResolver; private readonly ReaderParameters originalReaderParameters; private readonly AssemblyDefinition originalAssembly; private readonly TrimmedTestCaseResult testResult; @@ -69,6 +70,7 @@ public AssemblyChecker ( TrimmedTestCaseResult testResult) { this.originalsResolver = originalsResolver; + this.originalsTypeNameResolver = new TypeNameResolver (new TestResolver (), new TestAssemblyNameResolver (originalsResolver)); this.originalReaderParameters = originalReaderParameters; this.originalAssembly = original; this.testResult = testResult; @@ -1468,7 +1470,9 @@ internal IEnumerable VerifyLinkingOfOtherAssemblies (AssemblyDefinition } var expectedTypeName = checkAttrInAssembly.ConstructorArguments[1].Value.ToString ()!; - var expectedType = originalTargetAssembly.MainModule.GetType(expectedTypeName); + if (!originalsTypeNameResolver.TryResolveTypeName (originalTargetAssembly, expectedTypeName, out TypeReference? expectedTypeRef, out _)) + Assert.Fail($"Could not resolve original type `{expectedTypeName}' in assembly {assemblyName}"); + TypeDefinition expectedType = expectedTypeRef.Resolve (); linkedMembersInAssembly.TryGetValue(new AssemblyQualifiedToken(expectedType), out LinkedEntity? linkedTypeEntity); MetadataType? linkedType = linkedTypeEntity?.Entity as MetadataType; diff --git a/src/tools/illink/external/corert/README.md b/src/tools/illink/external/corert/README.md deleted file mode 100644 index babf7d8e26fa08..00000000000000 --- a/src/tools/illink/external/corert/README.md +++ /dev/null @@ -1 +0,0 @@ -The code in this folder was adapted from dotnet/corert commit c8bfca5f4554badfb89b80d2319769f83512bf62 \ No newline at end of file diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs deleted file mode 100644 index b8fe76cf2fc468..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameFormatter.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Text; -using System.Globalization; -using System.Collections.Generic; - -namespace System.Reflection -{ - internal static class AssemblyNameFormatter - { - public static string ComputeDisplayName(RuntimeAssemblyName a) - { - const int PUBLIC_KEY_TOKEN_LEN = 8; - - if (string.IsNullOrEmpty(a.Name)) - throw new FileLoadException(); - - StringBuilder sb = new StringBuilder(); - if (a.Name != null) - { - sb.AppendQuoted(a.Name); - } - - if (a.Version != null) - { - Version canonicalizedVersion = a.Version.CanonicalizeVersion(); - if (canonicalizedVersion.Major != ushort.MaxValue) - { - sb.Append(", Version="); - sb.Append(canonicalizedVersion.Major); - - if (canonicalizedVersion.Minor != ushort.MaxValue) - { - sb.Append('.'); - sb.Append(canonicalizedVersion.Minor); - - if (canonicalizedVersion.Build != ushort.MaxValue) - { - sb.Append('.'); - sb.Append(canonicalizedVersion.Build); - - if (canonicalizedVersion.Revision != ushort.MaxValue) - { - sb.Append('.'); - sb.Append(canonicalizedVersion.Revision); - } - } - } - } - } - - string cultureName = a.CultureName; - if (cultureName != null) - { - if (cultureName.Length == 0) - cultureName = "neutral"; - sb.Append(", Culture="); - sb.AppendQuoted(cultureName); - } - - byte[] pkt = a.PublicKeyOrToken; - if (pkt != null) - { - if (pkt.Length > PUBLIC_KEY_TOKEN_LEN) - throw new ArgumentException("Invalid token length", nameof(a)); - - sb.Append(", PublicKeyToken="); - if (pkt.Length == 0) - sb.Append("null"); - else - { - foreach (byte b in pkt) - { - sb.Append(b.ToString("x2", CultureInfo.InvariantCulture)); - } - } - } - - if (0 != (a.Flags & AssemblyNameFlags.Retargetable)) - sb.Append(", Retargetable=Yes"); - - AssemblyContentType contentType = a.Flags.ExtractAssemblyContentType(); - if (contentType == AssemblyContentType.WindowsRuntime) - sb.Append(", ContentType=WindowsRuntime"); - - // NOTE: By design (desktop compat) AssemblyName.FullName and ToString() do not include ProcessorArchitecture. - - return sb.ToString(); - } - - private static void AppendQuoted(this StringBuilder sb, string s) - { - bool needsQuoting = false; - const char quoteChar = '\"'; - - // App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthority) picks one - // by some algorithm. Rather than guess at it, we use double quotes consistently. - if (s != s.Trim() || s.Contains('"') || s.Contains('\'')) - needsQuoting = true; - - if (needsQuoting) - sb.Append(quoteChar); - - for (int i = 0; i < s.Length; i++) - { - bool addedEscape = false; - foreach (KeyValuePair kv in EscapeSequences) - { - string escapeReplacement = kv.Value; - if (!(s[i] == escapeReplacement[0])) - continue; - if ((s.Length - i) < escapeReplacement.Length) - continue; - if (s.Substring(i, escapeReplacement.Length).Equals(escapeReplacement)) - { - sb.Append('\\'); - sb.Append(kv.Key); - addedEscape = true; - } - } - - if (!addedEscape) - sb.Append(s[i]); - } - - if (needsQuoting) - sb.Append(quoteChar); - } - - private static Version CanonicalizeVersion(this Version version) - { - ushort major = (ushort)version.Major; - ushort minor = (ushort)version.Minor; - ushort build = (ushort)version.Build; - ushort revision = (ushort)version.Revision; - - if (major == version.Major && minor == version.Minor && build == version.Build && revision == version.Revision) - return version; - - return new Version(major, minor, build, revision); - } - - public static KeyValuePair[] EscapeSequences = - { - new KeyValuePair('\\', "\\"), - new KeyValuePair(',', ","), - new KeyValuePair('=', "="), - new KeyValuePair('\'', "'"), - new KeyValuePair('\"', "\""), - new KeyValuePair('n', Environment.NewLine), - new KeyValuePair('t', "\t"), - }; - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameHelpers.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameHelpers.cs deleted file mode 100644 index d6db056956eb8c..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameHelpers.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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.Globalization; -using System.IO; -using System.Text; -using System.Collections.Generic; - -namespace System.Reflection -{ - public static partial class AssemblyNameHelpers - { - - - // - // These helpers convert between the combined flags+contentType+processorArchitecture value and the separated parts. - // - // Since these are only for trusted callers, they do NOT check for out of bound bits. - // - - internal static AssemblyContentType ExtractAssemblyContentType(this AssemblyNameFlags flags) - { - return (AssemblyContentType)((((int)flags) >> 9) & 0x7); - } - - internal static ProcessorArchitecture ExtractProcessorArchitecture(this AssemblyNameFlags flags) - { - return (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); - } - - public static AssemblyNameFlags ExtractAssemblyNameFlags(this AssemblyNameFlags combinedFlags) - { - return combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); - } - - internal static AssemblyNameFlags CombineAssemblyNameFlags(AssemblyNameFlags flags, AssemblyContentType contentType, ProcessorArchitecture processorArchitecture) - { - return (AssemblyNameFlags)(((int)flags) | (((int)contentType) << 9) | ((int)processorArchitecture << 4)); - } - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameLexer.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameLexer.cs deleted file mode 100644 index 060f605e6a94d7..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameLexer.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Text; -using System.Collections.Generic; - -namespace System.Reflection -{ - // - // A simple lexer for assembly display names. - // - internal struct AssemblyNameLexer - { - internal AssemblyNameLexer(string s) - { - // Convert string to char[] with NUL terminator. (An actual NUL terminator in the input string will be treated - // as an actual end of string: this is compatible with desktop behavior.) - char[] chars = new char[s.Length + 1]; - s.CopyTo(0, chars, 0, s.Length); - _chars = chars; - _index = 0; - } - - // - // Return the next token in assembly name. If you expect the result to be DisplayNameToken.String, - // use GetNext(out String) instead. - // - internal Token GetNext() - { - return GetNext(out _); - } - - // - // Return the next token in assembly name. If the result is DisplayNameToken.String, - // sets "tokenString" to the tokenized string. - // - internal Token GetNext(out string? tokenString) - { - tokenString = null; - while (char.IsWhiteSpace(_chars[_index])) - _index++; - - char c = _chars[_index++]; - if (c == 0) - return Token.End; - if (c == ',') - return Token.Comma; - if (c == '=') - return Token.Equals; - - StringBuilder sb = new StringBuilder(); - - char quoteChar = (char)0; - if (c == '\'' || c == '\"') - { - quoteChar = c; - c = _chars[_index++]; - } - - for (; ; ) - { - if (c == 0) - { - _index--; - break; // Terminate: End of string (desktop compat: if string was quoted, permitted to terminate without end-quote.) - } - - if (quoteChar != 0 && c == quoteChar) - break; // Terminate: Found closing quote of quoted string. - - if (quoteChar == 0 && (c == ',' || c == '=')) - { - _index--; - break; // Terminate: Found start of a new ',' or '=' token. - } - - if (quoteChar == 0 && (c == '\'' || c == '\"')) - throw new FileLoadException(); // Desktop compat: Unescaped quote illegal unless entire string is quoted. - - if (c == '\\') - { - c = _chars[_index++]; - bool matched = false; - foreach (KeyValuePair kv in AssemblyNameFormatter.EscapeSequences) - { - if (c == kv.Key) - { - matched = true; - sb.Append(kv.Value); - break; - } - } - if (!matched) - throw new FileLoadException(); // Unrecognized escape - } - else - { - sb.Append(c); - } - - c = _chars[_index++]; - } - - tokenString = sb.ToString(); - if (quoteChar == 0) - tokenString = tokenString.Trim(); // Unless quoted, whitespace at beginning or end doesn't count. - return Token.String; - } - - // Token categories for display name lexer. - internal enum Token - { - Equals = 1, - Comma = 2, - String = 3, - End = 4, - } - - private readonly char[] _chars; - private int _index; - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameParser.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameParser.cs deleted file mode 100644 index b7463367819f96..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/AssemblyNameParser.cs +++ /dev/null @@ -1,217 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Diagnostics; -using System.Globalization; -using System.Collections.Generic; - -namespace System.Reflection -{ - // - // Parses an assembly name. - // - internal static class AssemblyNameParser - { - internal static RuntimeAssemblyName Parse(string s) - { - Debug.Assert(s != null); - - int indexOfNul = s.IndexOf((char)0); - if (indexOfNul != -1) - s = s.Substring(0, indexOfNul); - if (s.Length == 0) - throw new ArgumentException("Empty string", nameof(s)); - - AssemblyNameLexer lexer = new AssemblyNameLexer(s); - - // Name must come first. - string? name; - AssemblyNameLexer.Token token = lexer.GetNext(out name); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(); - - if (string.IsNullOrEmpty(name) || name.IndexOfAny(s_illegalCharactersInSimpleName) != -1) - throw new FileLoadException(); - - Version? version = null; - string? cultureName = null; - byte[]? pkt = null; - AssemblyNameFlags flags = 0; - - List alreadySeen = new List(); - token = lexer.GetNext(); - while (token != AssemblyNameLexer.Token.End) - { - if (token != AssemblyNameLexer.Token.Comma) - throw new FileLoadException(); - string? attributeName; - token = lexer.GetNext(out attributeName); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(); - token = lexer.GetNext(); - - // Compat note: Inside AppX apps, the desktop CLR's AssemblyName parser skips past any elements that don't follow the "=" pattern. - // (when running classic Windows apps, such an illegal construction throws an exception as expected.) - // Naturally, at least one app unwittingly takes advantage of this. - if (token == AssemblyNameLexer.Token.Comma || token == AssemblyNameLexer.Token.End) - continue; - - if (token != AssemblyNameLexer.Token.Equals) - throw new FileLoadException(); - string? attributeValue; - token = lexer.GetNext(out attributeValue); - if (token != AssemblyNameLexer.Token.String) - throw new FileLoadException(); - - if (string.IsNullOrEmpty(attributeName)) - throw new FileLoadException(); - - for (int i = 0; i < alreadySeen.Count; i++) - { - if (alreadySeen[i].Equals(attributeName, StringComparison.OrdinalIgnoreCase)) - throw new FileLoadException(); // Cannot specify the same attribute twice. - } - Debug.Assert(attributeValue is not null); - alreadySeen.Add(attributeName); - if (attributeName.Equals("Version", StringComparison.OrdinalIgnoreCase)) - { - version = ParseVersion(attributeValue); - } - - if (attributeName.Equals("Culture", StringComparison.OrdinalIgnoreCase)) - { - cultureName = ParseCulture(attributeValue); - } - - if (attributeName.Equals("PublicKeyToken", StringComparison.OrdinalIgnoreCase)) - { - pkt = ParsePKT(attributeValue); - } - - if (attributeName.Equals("ProcessorArchitecture", StringComparison.OrdinalIgnoreCase)) - { - flags |= (AssemblyNameFlags)(((int)ParseProcessorArchitecture(attributeValue)) << 4); - } - - if (attributeName.Equals("Retargetable", StringComparison.OrdinalIgnoreCase)) - { - if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) - flags |= AssemblyNameFlags.Retargetable; - else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) - { - // nothing to do - } - else - throw new FileLoadException(); - } - - if (attributeName.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) - { - if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) - flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); - else - throw new FileLoadException(); - } - - // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it (as long it's not duplicated.) - token = lexer.GetNext(); - } - return new RuntimeAssemblyName(name!, version!, cultureName!, flags, pkt!); - } - - private static Version ParseVersion(string attributeValue) - { - string[] parts = attributeValue.Split('.'); - if (parts.Length > 4) - throw new FileLoadException(); - ushort[] versionNumbers = new ushort[4]; - for (int i = 0; i < versionNumbers.Length; i++) - { - if (i >= parts.Length) - versionNumbers[i] = ushort.MaxValue; - else - { - // Desktop compat: TryParse is a little more forgiving than Fusion. - for (int j = 0; j < parts[i].Length; j++) - { - if (!char.IsDigit(parts[i][j])) - throw new FileLoadException(); - } - if (!(ushort.TryParse(parts[i], out versionNumbers[i]))) - { - throw new FileLoadException(); - } - } - } - - if (versionNumbers[0] == ushort.MaxValue || versionNumbers[1] == ushort.MaxValue) - throw new FileLoadException(); - if (versionNumbers[2] == ushort.MaxValue) - return new Version(versionNumbers[0], versionNumbers[1]); - if (versionNumbers[3] == ushort.MaxValue) - return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2]); - return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); - } - - private static string ParseCulture(string attributeValue) - { - if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) - { - return ""; - } - else - { - CultureInfo culture = CultureInfo.GetCultureInfo(attributeValue); // Force a CultureNotFoundException if not a valid culture. - return culture.Name; - } - } - - private static byte[] ParsePKT(string attributeValue) - { - if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue.Length == 0) - return Array.Empty(); - - if (attributeValue.Length != 8 * 2) - throw new FileLoadException(); - - byte[] pkt = new byte[8]; - int srcIndex = 0; - for (int i = 0; i < 8; i++) - { - char hi = attributeValue[srcIndex++]; - char lo = attributeValue[srcIndex++]; - pkt[i] = (byte)((ParseHexNybble(hi) << 4) | ParseHexNybble(lo)); - } - return pkt; - } - - private static ProcessorArchitecture ParseProcessorArchitecture(string attributeValue) - { - if (attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.MSIL; - if (attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.X86; - if (attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.IA64; - if (attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Amd64; - if (attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase)) - return ProcessorArchitecture.Arm; - throw new FileLoadException(); - } - - private static byte ParseHexNybble(char c) - { - if (c >= '0' && c <= '9') - return (byte)(c - '0'); - if (c >= 'a' && c <= 'f') - return (byte)(c - 'a' + 10); - if (c >= 'A' && c <= 'F') - return (byte)(c - 'A' + 10); - throw new FileLoadException(); - } - - private static readonly char[] s_illegalCharactersInSimpleName = { '/', '\\', ':' }; - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/RuntimeAssemblyName.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/RuntimeAssemblyName.cs deleted file mode 100644 index 4c340ea07deb0b..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/shared/System/Reflection/RuntimeAssemblyName.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; - -namespace System.Reflection -{ - // - // This is a private assembly name abstraction that's more suitable for use as keys in our caches. - // - // - Immutable, unlike the public AssemblyName - // - Has a useful Equals() override, unlike the public AssemblyName. - // - // We use this as our internal interchange type and only convert to and from the public AssemblyName class at public boundaries. - // - public sealed class RuntimeAssemblyName : IEquatable - { - public RuntimeAssemblyName(string name, Version version, string cultureName, AssemblyNameFlags flags, byte[] publicKeyOrToken) - { - Debug.Assert(name != null); - this.Name = name; - - // Optional version. - this.Version = version; - - // Optional culture name. - this.CultureName = cultureName; - - // Optional flags (this is actually an OR of the classic flags and the ContentType.) - this.Flags = flags; - - // Optional public key (if Flags.PublicKey == true) or public key token. - this.PublicKeyOrToken = publicKeyOrToken; - } - - // Simple name. - public string Name { get; } - - // Optional version. - public Version Version { get; } - - // Optional culture name. - public string CultureName { get; } - - // Optional flags (this is actually an OR of the classic flags and the ContentType.) - public AssemblyNameFlags Flags { get; } - - // Optional public key (if Flags.PublicKey == true) or public key token. - public byte[] PublicKeyOrToken { get; } - - // Equality - this compares every bit of data in the RuntimeAssemblyName which is acceptable for use as keys in a cache - // where semantic duplication is permissible. This method is *not* meant to define ref->def binding rules or - // assembly binding unification rules. - public bool Equals(RuntimeAssemblyName? other) - { - if (other == null) - return false; - if (!this.Name.Equals(other.Name)) - return false; - if (this.Version == null) - { - if (other.Version != null) - return false; - } - else - { - if (!this.Version.Equals(other.Version)) - return false; - } - if (!string.Equals(this.CultureName, other.CultureName)) - return false; - if (this.Flags != other.Flags) - return false; - - byte[] thisPK = this.PublicKeyOrToken; - byte[] otherPK = other.PublicKeyOrToken; - if (thisPK == null) - { - if (otherPK != null) - return false; - } - else if (otherPK == null) - { - return false; - } - else if (thisPK.Length != otherPK.Length) - { - return false; - } - else - { - for (int i = 0; i < thisPK.Length; i++) - { - if (thisPK[i] != otherPK[i]) - return false; - } - } - - return true; - } - - public sealed override bool Equals(object? obj) - { - RuntimeAssemblyName? other = obj as RuntimeAssemblyName; - if (other == null) - return false; - return Equals(other); - } - - public sealed override int GetHashCode() - { - return this.Name.GetHashCode(); - } - - public string FullName - { - get - { - return AssemblyNameFormatter.ComputeDisplayName(this); - } - } - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs deleted file mode 100644 index ba045487bc0737..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; - -namespace System.Reflection.Runtime.TypeParsing -{ - // - // String tokenizer for typenames passed to the GetType() api's. - // - internal sealed class TypeLexer - { - public TypeLexer(string s) - { - // Turn the string into a char array with a NUL terminator. - char[] chars = new char[s.Length + 1]; - s.CopyTo(0, chars, 0, s.Length); - _chars = chars; - _index = 0; - } - - public TokenType Peek - { - get - { - SkipWhiteSpace(); - char c = _chars[_index]; - return CharToToken(c); - } - } - - public TokenType PeekSecond - { - get - { - SkipWhiteSpace(); - int index = _index + 1; - while (char.IsWhiteSpace(_chars[index])) - index++; - char c = _chars[index]; - return CharToToken(c); - } - } - - - public void Skip() - { - Debug.Assert(_index != _chars.Length); - SkipWhiteSpace(); - _index++; - } - - // Return the next token and skip index past it unless already at end of string - // or the token is not a reserved token. - public TokenType GetNextToken() - { - TokenType tokenType = Peek; - if (tokenType == TokenType.End || tokenType == TokenType.Other) - return tokenType; - Skip(); - return tokenType; - } - - // - // Lex the next segment as part of a type name. (Do not use for assembly names.) - // - // Note that unescaped "."'s do NOT terminate the identifier, but unescaped "+"'s do. - // - // Terminated by the first non-escaped reserved character ('[', ']', '+', '&', '*' or ',') - // - public string GetNextIdentifier() - { - SkipWhiteSpace(); - - int src = _index; - char[] buffer = new char[_chars.Length]; - int dst = 0; - for (; ; ) - { - char c = _chars[src]; - TokenType token = CharToToken(c); - if (token != TokenType.Other) - break; - src++; - if (c == '\\') - { - c = _chars[src]; - if (c != NUL) - src++; - if (c == NUL || CharToToken(c) == TokenType.Other) - { - // If we got here, a backslash was used to escape a character that is not legal to escape inside a type name. - // - // Common sense would dictate throwing an ArgumentException but that's not what the desktop CLR does. - // The desktop CLR treats this case by returning FALSE from TypeName::TypeNameParser::GetIdentifier(). - // Unfortunately, no one checks this return result. Instead, the CLR keeps parsing (unfortunately, the lexer - // was left in some strange state by the previous failure but typically, this goes unnoticed) and eventually, tries to resolve - // a Type whose name is the empty string. When it can't resolve that type, the CLR throws a TypeLoadException() - // complaining about be unable to find a type with the empty name. - // - // To emulate this accidental behavior, we'll throw a special exception that's caught by the TypeParser. - // - throw new IllegalEscapeSequenceException(); - } - } - buffer[dst++] = c; - } - - _index = src; - return new string(buffer, 0, dst); - } - - // - // Lex the next segment as the assembly name at the end of an assembly-qualified type name. (Do not use for - // assembly names embedded inside generic type arguments.) - // - // Terminated by NUL. There are no escape characters defined by the typename lexer (however, AssemblyName - // does have its own escape rules.) - // - public RuntimeAssemblyName GetNextAssemblyName() - { - SkipWhiteSpace(); - - int src = _index; - char[] buffer = new char[_chars.Length]; - int dst = 0; - for (; ; ) - { - char c = _chars[src]; - if (c == NUL) - break; - src++; - buffer[dst++] = c; - } - _index = src; - string fullName = new string(buffer, 0, dst); - return AssemblyNameParser.Parse(fullName); - } - - // - // Lex the next segment as an assembly name embedded inside a generic argument type. - // - // Terminated by an unescaped ']'. - // - public RuntimeAssemblyName GetNextEmbeddedAssemblyName() - { - SkipWhiteSpace(); - - int src = _index; - char[] buffer = new char[_chars.Length]; - int dst = 0; - for (; ; ) - { - char c = _chars[src]; - if (c == NUL) - throw new ArgumentException(); - if (c == ']') - break; - src++; - - // Backslash can be used to escape a ']' - any other backslash character is left alone (along with the backslash) - // for the AssemblyName parser to handle. - if (c == '\\' && _chars[src] == ']') - { - c = _chars[src++]; - } - buffer[dst++] = c; - } - _index = src; - var fullName = new string(buffer, 0, dst); - return AssemblyNameParser.Parse(fullName); - } - - // - // Classify a character as a TokenType. (Fortunately, all tokens in typename strings other than identifiers are single-character tokens.) - // - private static TokenType CharToToken(char c) - { - switch (c) - { - case NUL: - return TokenType.End; - case '[': - return TokenType.OpenSqBracket; - case ']': - return TokenType.CloseSqBracket; - case ',': - return TokenType.Comma; - case '+': - return TokenType.Plus; - case '*': - return TokenType.Asterisk; - case '&': - return TokenType.Ampersand; - default: - return TokenType.Other; - } - } - - // - // The desktop typename parser has a strange attitude towards whitespace. It throws away whitespace between punctuation tokens and whitespace - // preceeding identifiers or assembly names (and this cannot be escaped away). But whitespace between the end of an identifier - // and the punctuation that ends it is *not* ignored. - // - // In other words, GetType(" Foo") searches for "Foo" but GetType("Foo ") searches for "Foo ". - // - // Whitespace between the end of an assembly name and the punction mark that ends it is also not ignored by this parser, - // but this is irrelevant since the assembly name is then turned over to AssemblyName for parsing, which *does* ignore trailing whitespace. - // - private void SkipWhiteSpace() - { - while (char.IsWhiteSpace(_chars[_index])) - _index++; - } - - - private int _index; - private readonly char[] _chars; - private const char NUL = (char)0; - - - public sealed class IllegalEscapeSequenceException : Exception - { - } - } - - internal enum TokenType - { - End = 0, //At end of string - OpenSqBracket = 1, //'[' - CloseSqBracket = 2, //']' - Comma = 3, //',' - Plus = 4, //'+' - Asterisk = 5, //'*' - Ampersand = 6, //'&' - Other = 7, //Type identifier, AssemblyName or embedded AssemblyName. - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs deleted file mode 100644 index a8d20aedef086d..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeName.cs +++ /dev/null @@ -1,219 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Collections.Generic; - -namespace System.Reflection.Runtime.TypeParsing -{ - // - // The TypeName class is the base class for a family of types that represent the nodes in a parse tree for - // assembly-qualified type names. - // - public abstract class TypeName - { - public abstract override string ToString(); - } - - // - // Represents a parse of a type name optionally qualified by an assembly name. If present, the assembly name follows - // a comma following the type name. - // - public sealed class AssemblyQualifiedTypeName : TypeName - { - public AssemblyQualifiedTypeName(NonQualifiedTypeName typeName, RuntimeAssemblyName assemblyName) - { - Debug.Assert(typeName != null); - TypeName = typeName; - AssemblyName = assemblyName; - } - - public sealed override string ToString() - { - return TypeName.ToString() + ((AssemblyName == null) ? "" : ", " + AssemblyName.FullName); - } - - public RuntimeAssemblyName AssemblyName { get; } - public NonQualifiedTypeName TypeName { get; } - } - - // - // Base class for all non-assembly-qualified type names. - // - public abstract class NonQualifiedTypeName : TypeName - { - } - - // - // Base class for namespace or nested type. - // - internal abstract class NamedTypeName : NonQualifiedTypeName - { - } - - // - // Non-nested named type. The full name is the namespace-qualified name. For example, the FullName for - // System.Collections.Generic.IList<> is "System.Collections.Generic.IList`1". - // - internal sealed partial class NamespaceTypeName : NamedTypeName - { - public NamespaceTypeName(string[] namespaceParts, string name) - { - Debug.Assert(namespaceParts != null); - Debug.Assert(name != null); - - _name = name; - _namespaceParts = namespaceParts; - } - - public sealed override string ToString() - { - string fullName = ""; - for (int i = 0; i < _namespaceParts.Length; i++) - { - fullName += _namespaceParts[_namespaceParts.Length - i - 1]; - fullName += "."; - } - fullName += _name; - return fullName; - } - - private string _name; - private string[] _namespaceParts; - } - - // - // A nested type. The Name is the simple name of the type (not including any portion of its declaring type name.) - // - internal sealed class NestedTypeName : NamedTypeName - { - public NestedTypeName(string name, NamedTypeName declaringType) - { - Name = name; - DeclaringType = declaringType; - } - - public string Name { get; private set; } - public NamedTypeName DeclaringType { get; private set; } - - public sealed override string ToString() - { - // Cecil's format uses '/' instead of '+' for nested types. - return DeclaringType + "/" + Name; - } - } - - // - // Abstract base for array, byref and pointer type names. - // - internal abstract class HasElementTypeName : NonQualifiedTypeName - { - public HasElementTypeName(TypeName elementTypeName) - { - ElementTypeName = elementTypeName; - } - - public TypeName ElementTypeName { get; } - } - - // - // A single-dimensional zero-lower-bound array type name. - // - internal sealed class ArrayTypeName : HasElementTypeName - { - public ArrayTypeName(TypeName elementTypeName) - : base(elementTypeName) - { - } - - public sealed override string ToString() - { - return ElementTypeName + "[]"; - } - } - - // - // A multidim array type name. - // - internal sealed class MultiDimArrayTypeName : HasElementTypeName - { - public MultiDimArrayTypeName(TypeName elementTypeName, int rank) - : base(elementTypeName) - { - Rank = rank; - } - - public sealed override string ToString() - { - return ElementTypeName + "[" + (Rank == 1 ? "*" : new string(',', Rank - 1)) + "]"; - } - - public int Rank { get; } - } - - // - // A byref type. - // - internal sealed class ByRefTypeName : HasElementTypeName - { - public ByRefTypeName(TypeName elementTypeName) - : base(elementTypeName) - { - } - - public sealed override string ToString() - { - return ElementTypeName + "&"; - } - } - - // - // A pointer type. - // - internal sealed class PointerTypeName : HasElementTypeName - { - public PointerTypeName(TypeName elementTypeName) - : base(elementTypeName) - { - } - - public sealed override string ToString() - { - return ElementTypeName + "*"; - } - } - - // - // A constructed generic type. - // - internal sealed class ConstructedGenericTypeName : NonQualifiedTypeName - { - public ConstructedGenericTypeName(NamedTypeName genericType, IEnumerable genericArguments) - { - GenericType = genericType; - GenericArguments = genericArguments; - } - - public NamedTypeName GenericType { get; } - public IEnumerable GenericArguments { get; } - - public sealed override string ToString() - { - string s = GenericType.ToString(); - s += "["; - string sep = ""; - foreach (TypeName genericTypeArgument in GenericArguments) - { - s += sep; - sep = ","; - AssemblyQualifiedTypeName? assemblyQualifiedTypeArgument = genericTypeArgument as AssemblyQualifiedTypeName; - if (assemblyQualifiedTypeArgument == null || assemblyQualifiedTypeArgument.AssemblyName == null) - s += genericTypeArgument.ToString(); - else - s += "[" + genericTypeArgument.ToString() + "]"; - } - s += "]"; - return s; - } - } -} diff --git a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs b/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs deleted file mode 100644 index 712bfddf7793c8..00000000000000 --- a/src/tools/illink/external/corert/src/System.Private.CoreLib/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs +++ /dev/null @@ -1,226 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#pragma warning disable CA2208 -using System.Collections.Generic; - -namespace System.Reflection.Runtime.TypeParsing -{ - // - // Parser for type names passed to GetType() apis. - // - public sealed class TypeParser - { - // - // Parses a typename. The typename may be optionally postpended with a "," followed by a legal assembly name. - // - public static TypeName? ParseTypeName(string s) - { - try - { - return ParseAssemblyQualifiedTypeName(s); - } - catch (ArgumentException) - { - return null; - } - } - - // - // Parses a typename. The typename may be optionally postpended with a "," followed by a legal assembly name. - // - private static TypeName? ParseAssemblyQualifiedTypeName(string s) - { - if (string.IsNullOrEmpty(s)) - return null; - - // Desktop compat: a whitespace-only "typename" qualified by an assembly name throws an ArgumentException rather than - // a TypeLoadException. - int idx = 0; - while (idx < s.Length && char.IsWhiteSpace(s[idx])) - { - idx++; - } - if (idx < s.Length && s[idx] == ',') - throw new ArgumentException(); - - try - { - TypeParser parser = new TypeParser(s); - NonQualifiedTypeName typeName = parser.ParseNonQualifiedTypeName(); - TokenType token = parser._lexer.GetNextToken(); - if (token == TokenType.End) - return typeName; - if (token == TokenType.Comma) - { - RuntimeAssemblyName assemblyName = parser._lexer.GetNextAssemblyName(); - token = parser._lexer.Peek; - if (token != TokenType.End) - throw new ArgumentException(); - return new AssemblyQualifiedTypeName(typeName, assemblyName); - } - throw new ArgumentException(); - } - catch (TypeLexer.IllegalEscapeSequenceException) - { - // Emulates a CLR4.5 bug that causes any string that contains an illegal escape sequence to be parsed as the empty string. - return ParseAssemblyQualifiedTypeName(string.Empty); - } - } - - private TypeParser(string s) - { - _lexer = new TypeLexer(s); - } - - - // - // Parses a type name without any assembly name qualification. - // - private NonQualifiedTypeName ParseNonQualifiedTypeName() - { - // Parse the named type or constructed generic type part first. - NonQualifiedTypeName typeName = ParseNamedOrConstructedGenericTypeName(); - - // Iterate through any "has-element" qualifiers ([], &, *). - for (;;) - { - TokenType token = _lexer.Peek; - if (token == TokenType.End) - break; - if (token == TokenType.Asterisk) - { - _lexer.Skip(); - typeName = new PointerTypeName(typeName); - } - else if (token == TokenType.Ampersand) - { - _lexer.Skip(); - typeName = new ByRefTypeName(typeName); - } - else if (token == TokenType.OpenSqBracket) - { - _lexer.Skip(); - token = _lexer.GetNextToken(); - if (token == TokenType.Asterisk) - { - typeName = new MultiDimArrayTypeName(typeName, 1); - token = _lexer.GetNextToken(); - } - else - { - int rank = 1; - while (token == TokenType.Comma) - { - token = _lexer.GetNextToken(); - rank++; - } - if (rank == 1) - typeName = new ArrayTypeName(typeName); - else - typeName = new MultiDimArrayTypeName(typeName, rank); - } - if (token != TokenType.CloseSqBracket) - throw new ArgumentException(); - } - else - { - break; - } - } - return typeName; - } - - // - // Foo or Foo+Inner or Foo[String] or Foo+Inner[String] - // - private NonQualifiedTypeName ParseNamedOrConstructedGenericTypeName() - { - NamedTypeName namedType = ParseNamedTypeName(); - // Because "[" is used both for generic arguments and array indexes, we must peek two characters deep. - if (!(_lexer.Peek == TokenType.OpenSqBracket && (_lexer.PeekSecond == TokenType.Other || _lexer.PeekSecond == TokenType.OpenSqBracket))) - return namedType; - else - { - _lexer.Skip(); - List genericTypeArguments = new List(); - for (;;) - { - TypeName genericTypeArgument = ParseGenericTypeArgument(); - genericTypeArguments.Add(genericTypeArgument); - TokenType token = _lexer.GetNextToken(); - if (token == TokenType.CloseSqBracket) - break; - if (token != TokenType.Comma) - throw new ArgumentException(); - } - - return new ConstructedGenericTypeName(namedType, genericTypeArguments); - } - } - - // - // Foo or Foo+Inner - // - private NamedTypeName ParseNamedTypeName() - { - NamedTypeName namedType = ParseNamespaceTypeName(); - while (_lexer.Peek == TokenType.Plus) - { - _lexer.Skip(); - string nestedTypeName = _lexer.GetNextIdentifier(); - namedType = new NestedTypeName(nestedTypeName, namedType); - } - return namedType; - } - - // - // Non-nested named type. - // - private NamespaceTypeName ParseNamespaceTypeName() - { - string fullName = _lexer.GetNextIdentifier(); - string[] parts = fullName.Split('.'); - int numNamespaceParts = parts.Length - 1; - string[] namespaceParts = new string[numNamespaceParts]; - for (int i = 0; i < numNamespaceParts; i++) - namespaceParts[numNamespaceParts - i - 1] = parts[i]; - string name = parts[numNamespaceParts]; - return new NamespaceTypeName(namespaceParts, name); - } - - // - // Parse a generic argument. In particular, generic arguments can take the special form [,]. - // - private TypeName ParseGenericTypeArgument() - { - TokenType token = _lexer.GetNextToken(); - if (token == TokenType.Other) - { - NonQualifiedTypeName nonQualifiedTypeName = ParseNonQualifiedTypeName(); - return nonQualifiedTypeName; - } - else if (token == TokenType.OpenSqBracket) - { - RuntimeAssemblyName? assemblyName = null; - NonQualifiedTypeName typeName = ParseNonQualifiedTypeName(); - token = _lexer.GetNextToken(); - if (token == TokenType.Comma) - { - assemblyName = _lexer.GetNextEmbeddedAssemblyName(); - token = _lexer.GetNextToken(); - } - if (token != TokenType.CloseSqBracket) - throw new ArgumentException(); - if (assemblyName == null) - return typeName; - else - return new AssemblyQualifiedTypeName(typeName, assemblyName); - } - else - throw new ArgumentException(); - } - - private readonly TypeLexer _lexer; - } -} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 0e95901f271aca..01d04b0ca6f82c 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -35,7 +35,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Reflection.Runtime.TypeParsing; using System.Text.RegularExpressions; using ILCompiler.DependencyAnalysisFramework; using ILLink.Shared; @@ -46,6 +45,10 @@ using Mono.Collections.Generic; using Mono.Linker.Dataflow; +using AssemblyNameInfo = System.Reflection.Metadata.AssemblyNameInfo; +using TypeName = System.Reflection.Metadata.TypeName; +using TypeNameParseOptions = System.Reflection.Metadata.TypeNameParseOptions; + namespace Mono.Linker.Steps { @@ -2151,12 +2154,6 @@ protected virtual void DoAdditionalInstantiatedTypeProcessing (TypeDefinition ty if (property.Name == "TargetTypeName") { string targetTypeName = (string) property.Argument.Value; - TypeName? typeName = TypeParser.ParseTypeName (targetTypeName); - if (typeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) { - AssemblyDefinition? assembly = Context.TryResolve (assemblyQualifiedTypeName.AssemblyName.Name); - return assembly == null ? null : Context.TryResolve (assembly, targetTypeName); - } - return Context.TryResolve (asm, targetTypeName); } } diff --git a/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs b/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs index 60e87246c7d0d7..6a4c664074cdd6 100644 --- a/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs +++ b/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.PartVisitor.cs @@ -9,8 +9,7 @@ namespace Mono.Linker { - - public sealed partial class DocumentationSignatureGenerator + internal sealed partial class DocumentationSignatureGenerator { /// /// A visitor that generates the part of the documentation comment after the initial type diff --git a/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.cs b/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.cs index b76f714d520c62..8a13a977cf5014 100644 --- a/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.cs +++ b/src/tools/illink/src/linker/Linker/DocumentationSignatureGenerator.cs @@ -12,7 +12,7 @@ namespace Mono.Linker /// Adapted from Roslyn's DocumentationCommentIDVisitor: /// https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/DocumentationComments/DocumentationCommentIDVisitor.cs /// - public sealed partial class DocumentationSignatureGenerator + internal sealed partial class DocumentationSignatureGenerator { internal const string MethodPrefix = "M:"; internal const string FieldPrefix = "F:"; diff --git a/src/tools/illink/src/linker/Linker/DocumentationSignatureParser.cs b/src/tools/illink/src/linker/Linker/DocumentationSignatureParser.cs index 6b7d96ad5b09ab..eb2a3f4629e242 100644 --- a/src/tools/illink/src/linker/Linker/DocumentationSignatureParser.cs +++ b/src/tools/illink/src/linker/Linker/DocumentationSignatureParser.cs @@ -24,7 +24,7 @@ namespace Mono.Linker /// This API instead works with the Cecil OM. It can be used to refer to IL definitions /// where the signature of a member can contain references to instantiated generics. /// - public static class DocumentationSignatureParser + internal static class DocumentationSignatureParser { [Flags] public enum MemberType diff --git a/src/tools/illink/src/linker/Linker/ITryResolve.cs b/src/tools/illink/src/linker/Linker/ITryResolve.cs new file mode 100644 index 00000000000000..aa760547a3fb9c --- /dev/null +++ b/src/tools/illink/src/linker/Linker/ITryResolve.cs @@ -0,0 +1,21 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Cecil; + +#nullable enable + +namespace Mono.Linker +{ + internal interface ITryResolveMetadata + { + MethodDefinition? TryResolve (MethodReference methodReference); + TypeDefinition? TryResolve (TypeReference typeReference); + TypeDefinition? TryResolve (ExportedType exportedType); + } + + internal interface ITryResolveAssemblyName + { + AssemblyDefinition? TryResolve (string assemblyName); + } +} diff --git a/src/tools/illink/src/linker/Linker/LinkContext.cs b/src/tools/illink/src/linker/Linker/LinkContext.cs index 4d825e73d91822..31733b0c6ad565 100644 --- a/src/tools/illink/src/linker/Linker/LinkContext.cs +++ b/src/tools/illink/src/linker/Linker/LinkContext.cs @@ -59,13 +59,7 @@ public static class TargetRuntimeVersion public const int NET6 = 6; } - public interface ITryResolveMetadata - { - MethodDefinition? TryResolve (MethodReference methodReference); - TypeDefinition? TryResolve (TypeReference typeReference); - } - - public class LinkContext : IMetadataResolver, ITryResolveMetadata, IDisposable + public class LinkContext : IMetadataResolver, ITryResolveMetadata, ITryResolveAssemblyName, IDisposable { readonly Pipeline _pipeline; @@ -211,7 +205,7 @@ protected LinkContext (Pipeline pipeline, ILogger logger, string outputDirectory _logger = logger ?? throw new ArgumentNullException (nameof (logger)); _resolver = factory.CreateResolver (this); - _typeNameResolver = new TypeNameResolver (this); + _typeNameResolver = new TypeNameResolver (this, this); _actions = new Dictionary (); _parameters = new Dictionary (StringComparer.Ordinal); _customAttributes = new CustomAttributeSource (this); diff --git a/src/tools/illink/src/linker/Linker/ModuleDefinitionExtensions.cs b/src/tools/illink/src/linker/Linker/ModuleDefinitionExtensions.cs index 64ad1df836f6f0..b79ff38c7d7c85 100644 --- a/src/tools/illink/src/linker/Linker/ModuleDefinitionExtensions.cs +++ b/src/tools/illink/src/linker/Linker/ModuleDefinitionExtensions.cs @@ -4,18 +4,19 @@ using System.Diagnostics.CodeAnalysis; using Mono.Cecil; +#nullable enable + namespace Mono.Linker { - public static class ModuleDefinitionExtensions + internal static class ModuleDefinitionExtensions { - public static bool IsCrossgened (this ModuleDefinition module) { return (module.Attributes & ModuleAttributes.ILOnly) == 0 && (module.Attributes & ModuleAttributes.ILLibrary) != 0; } - public static bool GetMatchingExportedType (this ModuleDefinition module, TypeDefinition typeDefinition, LinkContext context, [NotNullWhen (true)] out ExportedType? exportedType) + public static bool GetMatchingExportedType (this ModuleDefinition module, TypeDefinition typeDefinition, ITryResolveMetadata context, [NotNullWhen (true)] out ExportedType? exportedType) { exportedType = null; if (!module.HasExportedTypes) diff --git a/src/tools/illink/src/linker/Linker/TypeNameResolver.WithDiagnostics.cs b/src/tools/illink/src/linker/Linker/TypeNameResolver.WithDiagnostics.cs new file mode 100644 index 00000000000000..24bd45aba1877f --- /dev/null +++ b/src/tools/illink/src/linker/Linker/TypeNameResolver.WithDiagnostics.cs @@ -0,0 +1,90 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using ILLink.Shared; +using ILLink.Shared.TrimAnalysis; +using Mono.Cecil; +using Mono.Linker; + +using TypeName = System.Reflection.Metadata.TypeName; +using AssemblyNameInfo = System.Reflection.Metadata.AssemblyNameInfo; + +namespace Mono.Linker +{ + internal sealed partial class TypeNameResolver + { + public bool TryResolveTypeName ( + string typeNameString, + in DiagnosticContext diagnosticContext, + [NotNullWhen (true)] out TypeReference? typeReference, + [NotNullWhen (true)] out List? typeResolutionRecords, + bool needsAssemblyName = true) + { + typeReference = null; + typeResolutionRecords = null; + if (string.IsNullOrEmpty (typeNameString)) + return false; + + if (!TypeName.TryParse (typeNameString, out TypeName? parsedTypeName, s_typeNameParseOptions)) + return false; + + typeResolutionRecords = new List (); + AssemblyDefinition? typeAssembly; + if (parsedTypeName.AssemblyName is AssemblyNameInfo assemblyName) { + typeAssembly = _assemblyResolver.TryResolve (assemblyName.Name); + if (typeAssembly is null) { + typeResolutionRecords = null; + return false; + } + + typeReference = ResolveTypeName (typeAssembly, parsedTypeName, typeResolutionRecords); + if (typeReference == null) { + typeResolutionRecords = null; + } + + return typeReference != null; + } + + // If parsedTypeName doesn't have an assembly name in it but it does have a namespace, + // search for the type in the calling object's assembly. If not found, look in the core + // assembly. + ICustomAttributeProvider? provider = diagnosticContext.Origin.Provider; + typeAssembly = provider switch { + AssemblyDefinition asm => asm, + TypeDefinition type => type.Module?.Assembly, + IMemberDefinition member => member.DeclaringType.Module.Assembly, + null => null, + _ => throw new NotSupportedException () + }; + + if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) + return true; + + // If type is not found in the caller's assembly, try in core assembly. + typeAssembly = _assemblyResolver.TryResolve (PlatformAssemblies.CoreLib); + if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) + return true; + + // It is common to use Type.GetType for looking if a type is available. + // If no type was found only warn and return null. + if (needsAssemblyName && provider != null) + diagnosticContext.AddDiagnostic (DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeNameString); + + typeResolutionRecords = null; + return false; + + bool TryResolveTypeName (AssemblyDefinition assemblyDefinition, TypeName? typeName, [NotNullWhen (true)] out TypeReference? typeReference, List typeResolutionRecords) + { + typeReference = null; + if (assemblyDefinition == null) + return false; + + typeReference = ResolveTypeName (assemblyDefinition, typeName, typeResolutionRecords); + return typeReference != null; + } + } + } +} diff --git a/src/tools/illink/src/linker/Linker/TypeNameResolver.cs b/src/tools/illink/src/linker/Linker/TypeNameResolver.cs index cd429719b891a5..3bb0e4452cb2dd 100644 --- a/src/tools/illink/src/linker/Linker/TypeNameResolver.cs +++ b/src/tools/illink/src/linker/Linker/TypeNameResolver.cs @@ -1,103 +1,33 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Reflection.Runtime.TypeParsing; -using ILLink.Shared; -using ILLink.Shared.TrimAnalysis; using Mono.Cecil; +using TypeName = System.Reflection.Metadata.TypeName; +using TypeNameParseOptions = System.Reflection.Metadata.TypeNameParseOptions; +using AssemblyNameInfo = System.Reflection.Metadata.AssemblyNameInfo; +using TypeNameHelpers = System.Reflection.Metadata.TypeNameHelpers; + +#nullable enable + namespace Mono.Linker { - internal sealed class TypeNameResolver + internal sealed partial class TypeNameResolver { - readonly LinkContext _context; + readonly ITryResolveMetadata _metadataResolver; + readonly ITryResolveAssemblyName _assemblyResolver; + + private static readonly TypeNameParseOptions s_typeNameParseOptions = new () { MaxNodes = int.MaxValue }; public readonly record struct TypeResolutionRecord (AssemblyDefinition ReferringAssembly, TypeDefinition ResolvedType); - public TypeNameResolver (LinkContext context) + public TypeNameResolver (ITryResolveMetadata metadataResolver, ITryResolveAssemblyName assemblyNameResolver) { - _context = context; - } - - public bool TryResolveTypeName ( - string typeNameString, - in DiagnosticContext diagnosticContext, - [NotNullWhen (true)] out TypeReference? typeReference, - [NotNullWhen (true)] out List? typeResolutionRecords, - bool needsAssemblyName = true) - { - typeReference = null; - typeResolutionRecords = null; - if (string.IsNullOrEmpty (typeNameString)) - return false; - - TypeName? parsedTypeName; - try { - parsedTypeName = TypeParser.ParseTypeName (typeNameString); - } catch (ArgumentException) { - return false; - } catch (System.IO.FileLoadException) { - return false; - } - - typeResolutionRecords = new List (); - AssemblyDefinition? typeAssembly; - if (parsedTypeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) { - typeAssembly = _context.TryResolve (assemblyQualifiedTypeName.AssemblyName.Name); - if (typeAssembly == null) { - typeResolutionRecords = null; - return false; - } - - typeReference = ResolveTypeName (typeAssembly, assemblyQualifiedTypeName.TypeName, typeResolutionRecords); - if (typeReference == null) { - typeResolutionRecords = null; - } - - return typeReference != null; - } - - // If parsedTypeName doesn't have an assembly name in it but it does have a namespace, - // search for the type in the calling object's assembly. If not found, look in the core - // assembly. - ICustomAttributeProvider? provider = diagnosticContext.Origin.Provider; - typeAssembly = provider switch { - AssemblyDefinition asm => asm, - TypeDefinition type => type.Module?.Assembly, - IMemberDefinition member => member.DeclaringType.Module.Assembly, - null => null, - _ => throw new NotSupportedException () - }; - - if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) - return true; - - // If type is not found in the caller's assembly, try in core assembly. - typeAssembly = _context.TryResolve (PlatformAssemblies.CoreLib); - if (typeAssembly != null && TryResolveTypeName (typeAssembly, parsedTypeName, out typeReference, typeResolutionRecords)) - return true; - - // It is common to use Type.GetType for looking if a type is available. - // If no type was found only warn and return null. - if (needsAssemblyName && provider != null) - diagnosticContext.AddDiagnostic (DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeNameString); - - typeResolutionRecords = null; - return false; - - bool TryResolveTypeName (AssemblyDefinition assemblyDefinition, TypeName? typeName, [NotNullWhen (true)] out TypeReference? typeReference, List typeResolutionRecords) - { - typeReference = null; - if (assemblyDefinition == null) - return false; - - typeReference = ResolveTypeName (assemblyDefinition, typeName, typeResolutionRecords); - return typeReference != null; - } + _metadataResolver = metadataResolver; + _assemblyResolver = assemblyNameResolver; } public bool TryResolveTypeName ( @@ -107,7 +37,11 @@ public bool TryResolveTypeName ( [NotNullWhen (true)] out List? typeResolutionRecords) { typeResolutionRecords = new List (); - typeReference = ResolveTypeName (assembly, TypeParser.ParseTypeName (typeNameString), typeResolutionRecords); + if (!TypeName.TryParse (typeNameString, out TypeName? parsedTypeName, s_typeNameParseOptions)) { + typeReference = null; + return false; + } + typeReference = ResolveTypeName (assembly, parsedTypeName, typeResolutionRecords); if (typeReference == null) typeResolutionRecords = null; @@ -115,25 +49,27 @@ public bool TryResolveTypeName ( return typeReference != null; } - TypeReference? ResolveTypeName (AssemblyDefinition assembly, TypeName? typeName, List typeResolutionRecords) + TypeReference? ResolveTypeName (AssemblyDefinition originalAssembly, TypeName? typeName, List typeResolutionRecords) { - if (typeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) { + if (typeName == null) + return null; + + AssemblyDefinition? assembly = originalAssembly; + if (typeName.AssemblyName is AssemblyNameInfo assemblyName) // In this case we ignore the assembly parameter since the type name has assembly in it - var assemblyFromName = _context.TryResolve (assemblyQualifiedTypeName.AssemblyName.Name); - return assemblyFromName == null ? null : ResolveTypeName (assemblyFromName, assemblyQualifiedTypeName.TypeName, typeResolutionRecords); - } + assembly = _assemblyResolver.TryResolve (assemblyName.Name); - if (assembly == null || typeName == null) + if (assembly == null) return null; - if (typeName is ConstructedGenericTypeName constructedGenericTypeName) { - var genericTypeRef = ResolveTypeName (assembly, constructedGenericTypeName.GenericType, typeResolutionRecords); + if (typeName.IsConstructedGenericType) { + var genericTypeRef = ResolveTypeName (assembly, typeName.GetGenericTypeDefinition (), typeResolutionRecords); if (genericTypeRef == null) return null; Debug.Assert (genericTypeRef is TypeDefinition); var genericInstanceType = new GenericInstanceType (genericTypeRef); - foreach (var arg in constructedGenericTypeName.GenericArguments) { + foreach (var arg in typeName.GetGenericArguments()) { var genericArgument = ResolveTypeName (assembly, arg, typeResolutionRecords); if (genericArgument == null) return null; @@ -142,29 +78,62 @@ public bool TryResolveTypeName ( } return genericInstanceType; - } else if (typeName is HasElementTypeName elementTypeName) { - var elementType = ResolveTypeName (assembly, elementTypeName.ElementTypeName, typeResolutionRecords); + } else if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) { + var elementType = ResolveTypeName (assembly, typeName.GetElementType (), typeResolutionRecords); if (elementType == null) return null; - return typeName switch { - ArrayTypeName => new ArrayType (elementType), - MultiDimArrayTypeName multiDimArrayTypeName => new ArrayType (elementType, multiDimArrayTypeName.Rank), - ByRefTypeName => new ByReferenceType (elementType), - PointerTypeName => new PointerType (elementType), - _ => elementType - }; + if (typeName.IsArray) + return typeName.IsSZArray ? new ArrayType (elementType) : new ArrayType (elementType, typeName.GetArrayRank ()); + if (typeName.IsByRef) + return new ByReferenceType (elementType); + if (typeName.IsPointer) + return new PointerType (elementType); + Debug.Fail("Unreachable"); + return null; } - TypeDefinition? resolvedType = assembly.MainModule.ResolveType (typeName.ToString (), _context); + Debug.Assert (typeName.IsSimple); + TypeName topLevelTypeName = typeName; + while (topLevelTypeName.IsNested) + topLevelTypeName = topLevelTypeName.DeclaringType!; + Debug.Assert (topLevelTypeName.AssemblyName == typeName.AssemblyName); + TypeDefinition? resolvedType = GetSimpleTypeFromModule (typeName, assembly.MainModule); // True type references (like generics and arrays) don't count as actually resolved types, they're just wrappers // so only record type resolutions for types which are actually resolved. if (resolvedType != null) { typeResolutionRecords.Add (new (assembly, resolvedType)); + return resolvedType; } - return resolvedType; + return null; + + TypeDefinition? GetSimpleTypeFromModule (TypeName typeName, ModuleDefinition module) + { + if (typeName.IsNested) + { + TypeDefinition? type = GetSimpleTypeFromModule (typeName.DeclaringType!, module); + if (type == null) + return null; + return GetNestedType (type, TypeNameHelpers.Unescape (typeName.Name)); + } + + return module.ResolveType (TypeNameHelpers.Unescape (typeName.FullName), _metadataResolver); + } + + TypeDefinition? GetNestedType (TypeDefinition type, string nestedTypeName) + { + if (!type.HasNestedTypes) + return null; + + foreach (var nestedType in type.NestedTypes) { + if (nestedType.Name == nestedTypeName) + return nestedType; + } + + return null; + } } } } diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs index 6189eae6d794cb..35f6ca0bd04d4e 100644 --- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs @@ -11,7 +11,7 @@ namespace Mono.Linker { - public static class TypeReferenceExtensions + internal static class TypeReferenceExtensions { public static string GetDisplayName (this TypeReference type) { diff --git a/src/tools/illink/src/linker/Mono.Linker.csproj b/src/tools/illink/src/linker/Mono.Linker.csproj index 8241ceb22e40ad..5c151fad0e9639 100644 --- a/src/tools/illink/src/linker/Mono.Linker.csproj +++ b/src/tools/illink/src/linker/Mono.Linker.csproj @@ -23,6 +23,7 @@ $(NoWarn);NU5131 $(TargetsForTfmSpecificContentInPackage);_AddReferenceAssemblyToPackage $(DefineConstants);ILLINK + true @@ -73,7 +74,12 @@ - + + + + + + diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/Dependencies/EscapedTypeNames.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/Dependencies/EscapedTypeNames.il new file mode 100644 index 00000000000000..392f5903be75eb --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/Dependencies/EscapedTypeNames.il @@ -0,0 +1,28 @@ +// Metadata version: v4.0.30319 +.assembly extern System.Runtime +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: +} +.assembly 'library' +{ + .hash algorithm 0x00008004 + .ver 1:0:0:0 +} +.module library.dll + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi sealed beforefieldinit 'Library.Not+Nested' + extends [System.Runtime]System.Object +{ + + .class nested public auto ansi sealed beforefieldinit 'Nes\\ted' + extends [System.Runtime]System.Object + { + } + + .class nested public auto ansi sealed beforefieldinit 'Nes/ted' + extends [System.Runtime]System.Object + { + } +} // end of class Library.TypeInfoCalls diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs index 981ad6227ceb8d..dcf6be970e8197 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs @@ -1,13 +1,19 @@ -using System; +using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Helpers; +using Mono.Linker.Tests.Cases.Expectations.Metadata; namespace Mono.Linker.Tests.Cases.Reflection { [KeptMember (".cctor()")] [ExpectedNoWarnings ()] + [Define ("IL_ASSEMBLY_AVAILABLE")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/EscapedTypeNames.il" })] + [KeptTypeInAssembly ("library", "Library.Not\\+Nested")] + [KeptTypeInAssembly ("library", "Library.Not\\+Nested+Nes\\\\ted")] + [KeptTypeInAssembly ("library", "Library.Not\\+Nested+Nes/ted")] [KeptDelegateCacheField ("0", nameof (AssemblyResolver))] [KeptDelegateCacheField ("1", nameof (GetTypeFromAssembly))] public class TypeUsedViaReflection @@ -47,8 +53,8 @@ public static void Main () BaseTypeInterfaces.Test (); - TestInvalidTypeCombination (); + TestEscapedTypeName (); } [Kept] @@ -465,5 +471,13 @@ static void TestInvalidTypeCombination () Console.WriteLine (Type.GetType ("System.Span`1[[System.Byte, System.Runtime]][], System.Runtime")); } catch (Exception e) { } } + + [Kept] + static void TestEscapedTypeName () + { + var typeKept = Type.GetType ("Library.Not\\+Nested, library"); + typeKept = Type.GetType ("Library.Not\\+Nested+Nes\\\\ted, library"); + typeKept = Type.GetType ("Library.Not\\+Nested+Nes/ted, library"); + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index e9e9b94de191e4..f6480e554c3528 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -12,11 +12,14 @@ using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; +using Mono.Linker; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Extensions; using Mono.Linker.Tests.TestCasesRunner.ILVerification; +using ILLink.Shared.TrimAnalysis; using NUnit.Framework; +using System.Data.Common; namespace Mono.Linker.Tests.TestCasesRunner { @@ -24,6 +27,7 @@ public class ResultChecker { readonly BaseAssemblyResolver _originalsResolver; readonly BaseAssemblyResolver _linkedResolver; + readonly TypeNameResolver _linkedTypeNameResolver; readonly ReaderParameters _originalReaderParameters; readonly ReaderParameters _linkedReaderParameters; @@ -43,6 +47,7 @@ public ResultChecker (BaseAssemblyResolver originalsResolver, BaseAssemblyResolv { _originalsResolver = originalsResolver; _linkedResolver = linkedResolver; + _linkedTypeNameResolver = new TypeNameResolver (new TestResolver (), new TestAssemblyNameResolver (_linkedResolver)); _originalReaderParameters = originalReaderParameters; _linkedReaderParameters = linkedReaderParameters; } @@ -309,7 +314,11 @@ void VerifyLinkingOfOtherAssemblies (AssemblyDefinition original) } var expectedTypeName = checkAttrInAssembly.ConstructorArguments[1].Value.ToString (); - TypeDefinition linkedType = linkedAssembly.MainModule.GetType (expectedTypeName); + TypeReference linkedTypeRef = null; + try { + _linkedTypeNameResolver.TryResolveTypeName (linkedAssembly, expectedTypeName, out linkedTypeRef, out _); + } catch (AssemblyResolutionException) {} + TypeDefinition linkedType = linkedTypeRef?.Resolve (); if (linkedType == null && linkedAssembly.MainModule.HasExportedTypes) { ExportedType exportedType = linkedAssembly.MainModule.ExportedTypes diff --git a/src/tools/illink/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs b/src/tools/illink/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs index 7b442116c188f5..4d50fa3d812161 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs @@ -12,14 +12,6 @@ namespace Mono.Linker.Tests { - sealed class TestResolver : ITryResolveMetadata - { - public static TestResolver Instance => new TestResolver (); - - public MethodDefinition TryResolve (MethodReference methodReference) => methodReference.Resolve (); - public TypeDefinition TryResolve (TypeReference typeReference) => typeReference.Resolve (); - } - [TestFixture] public class DocumentationSignatureParserTests { @@ -51,7 +43,7 @@ public static void CheckUniqueParsedString (IMemberDefinition member, string inp { var module = (member as TypeDefinition)?.Module ?? member.DeclaringType?.Module; Assert.NotNull (module); - var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, TestResolver.Instance); + var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, new TestResolver ()); Assert.AreEqual (1, parseResults.Count ()); Assert.AreEqual (member, parseResults.First ()); } @@ -59,7 +51,7 @@ public static void CheckUniqueParsedString (IMemberDefinition member, string inp public static void CheckGeneratedString (IMemberDefinition member, string expected) { var builder = new StringBuilder (); - DocumentationSignatureGenerator.VisitMember (member, builder, TestResolver.Instance); + DocumentationSignatureGenerator.VisitMember (member, builder, new TestResolver ()); Assert.AreEqual (expected, builder.ToString ()); } @@ -67,7 +59,7 @@ public static void CheckParsedString (IMemberDefinition member, string input) { var module = (member as TypeDefinition)?.Module ?? member.DeclaringType?.Module; Assert.NotNull (module); - var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, TestResolver.Instance); + var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, new TestResolver ()); CollectionAssert.Contains (parseResults, member); } @@ -75,7 +67,7 @@ public static void CheckUnresolvedDocumentationSignature (IMemberDefinition memb { var module = (member as TypeDefinition)?.Module ?? member.DeclaringType?.Module; Assert.NotNull (module); - var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, TestResolver.Instance); + var parseResults = DocumentationSignatureParser.GetMembersForDocumentationSignature (input, module, new TestResolver ()); CollectionAssert.DoesNotContain (parseResults, member); } diff --git a/src/tools/illink/test/Mono.Linker.Tests/Tests/TypeNameResolverTests.cs b/src/tools/illink/test/Mono.Linker.Tests/Tests/TypeNameResolverTests.cs deleted file mode 100644 index de3759d46b4822..00000000000000 --- a/src/tools/illink/test/Mono.Linker.Tests/Tests/TypeNameResolverTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Reflection.Runtime.TypeParsing; -using NUnit.Framework; - -namespace Mono.Linker.Tests -{ - [TestFixture] - public class TypeNameResolverTests - { - [Test] - public void TryParseAssemblyQualifiedTypeName_Null () - { - Assert.IsNull (TypeParser.ParseTypeName (null)); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_FullyQualified () - { - var value = typeof (TypeNameResolverTests).AssemblyQualifiedName; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsTrue (typeName is AssemblyQualifiedTypeName); - AssemblyQualifiedTypeName assemblyQualifiedTypeName = (AssemblyQualifiedTypeName) typeName; - Assert.AreEqual (assemblyQualifiedTypeName.AssemblyName.FullName, typeof (TypeNameResolverTests).Assembly.FullName); - Assert.AreEqual (assemblyQualifiedTypeName.TypeName.ToString (), typeof (TypeNameResolverTests).FullName); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_NameAndAssemblyOnly () - { - var value = $"{typeof (TypeNameResolverTests).FullName}, {typeof (TypeNameResolverTests).Assembly.GetName ().Name}"; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsTrue (typeName is AssemblyQualifiedTypeName); - AssemblyQualifiedTypeName assemblyQualifiedTypeName = (AssemblyQualifiedTypeName) typeName; - Assert.AreEqual (assemblyQualifiedTypeName.AssemblyName.Name, typeof (TypeNameResolverTests).Assembly.GetName ().Name); - Assert.AreEqual (assemblyQualifiedTypeName.TypeName.ToString (), typeof (TypeNameResolverTests).FullName); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_NameOnly () - { - var value = typeof (TypeNameResolverTests).FullName; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsFalse (typeName is AssemblyQualifiedTypeName); - Assert.AreEqual (typeName.ToString (), value); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_GenericType_FullyQualified () - { - var value = typeof (GenericType<,>).AssemblyQualifiedName; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsTrue (typeName is AssemblyQualifiedTypeName); - AssemblyQualifiedTypeName assemblyQualifiedTypeName = (AssemblyQualifiedTypeName) typeName; - Assert.AreEqual (assemblyQualifiedTypeName.AssemblyName.Name, typeof (TypeNameResolverTests).Assembly.GetName ().Name); - Assert.AreEqual (assemblyQualifiedTypeName.TypeName.ToString (), $"{typeof (TypeNameResolverTests).FullName}/GenericType`2"); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_GenericType_NameAndAssemblyOnly () - { - var value = $"{typeof (GenericType<,>).FullName}, {typeof (TypeNameResolverTests).Assembly.GetName ().Name}"; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsTrue (typeName is AssemblyQualifiedTypeName); - AssemblyQualifiedTypeName assemblyQualifiedTypeName = (AssemblyQualifiedTypeName) typeName; - Assert.AreEqual (assemblyQualifiedTypeName.AssemblyName.Name, typeof (TypeNameResolverTests).Assembly.GetName ().Name); - Assert.AreEqual (assemblyQualifiedTypeName.TypeName.ToString (), $"{typeof (TypeNameResolverTests).FullName}/GenericType`2"); - } - - [Test] - public void TryParseAssemblyQualifiedTypeName_GenericType_NameOnly () - { - var value = typeof (GenericType<,>).FullName; - var typeName = TypeParser.ParseTypeName (value); - Assert.IsFalse (typeName is AssemblyQualifiedTypeName); - Assert.AreEqual (typeName.ToString (), $"{typeof (TypeNameResolverTests).FullName}/GenericType`2"); - } - - [Test] - public void MissingTypeName () - { - Assert.IsNull (TypeParser.ParseTypeName (", System")); - } - - sealed class GenericType { } - } -} diff --git a/src/tools/illink/test/Trimming.Tests.Shared/TestAssemblyNameResolver.cs b/src/tools/illink/test/Trimming.Tests.Shared/TestAssemblyNameResolver.cs new file mode 100644 index 00000000000000..f55dc4b9154a2a --- /dev/null +++ b/src/tools/illink/test/Trimming.Tests.Shared/TestAssemblyNameResolver.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Cecil; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + struct TestAssemblyNameResolver : ITryResolveAssemblyName + { + readonly BaseAssemblyResolver _assemblyResolver; + + public TestAssemblyNameResolver (BaseAssemblyResolver resolver) + { + _assemblyResolver = resolver; + } + + public AssemblyDefinition TryResolve (string assemblyName) + => _assemblyResolver.Resolve (new AssemblyNameReference (assemblyName, null), new ReaderParameters ()); + } +} diff --git a/src/tools/illink/test/Trimming.Tests.Shared/TestResolver.cs b/src/tools/illink/test/Trimming.Tests.Shared/TestResolver.cs new file mode 100644 index 00000000000000..af37fcfbe6487d --- /dev/null +++ b/src/tools/illink/test/Trimming.Tests.Shared/TestResolver.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Mono.Cecil; + +namespace Mono.Linker.Tests.TestCasesRunner +{ + struct TestResolver : ITryResolveMetadata + { + public MethodDefinition TryResolve (MethodReference methodReference) => methodReference.Resolve (); + + public TypeDefinition TryResolve (TypeReference typeReference) => typeReference.Resolve (); + + public TypeDefinition TryResolve (ExportedType exportedType) => exportedType.Resolve (); + } +}