From c642678f7fce5c0edff665c5c0dc18186c6ddcd1 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 2 Aug 2025 14:37:51 +0200 Subject: [PATCH] Remove ToTypeReference: Implement ParseReflectionName with SRM TypeName. --- .../Semantics/ConversionTests.cs | 71 ++++-- .../Semantics/ExplicitConversionTest.cs | 7 +- .../TypeSystem/ReflectionHelperTests.cs | 49 ++-- .../CSharp/Syntax/AstType.cs | 40 --- .../CSharp/Syntax/ComposedType.cs | 27 -- .../CSharp/Syntax/FunctionPointerAstType.cs | 10 - .../CSharp/Syntax/InvocationAstType.cs | 11 - .../CSharp/Syntax/MemberType.cs | 37 --- .../CSharp/Syntax/PrimitiveType.cs | 17 -- .../CSharp/Syntax/SimpleType.cs | 28 --- .../CSharp/Syntax/TupleAstType.cs | 14 -- .../TypeSystem/ReflectionHelper.cs | 232 ++++++++---------- .../TypeSystem/TypeSystemExtensions.cs | 20 ++ 13 files changed, 203 insertions(+), 360 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs b/ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs index 2c141d14a..4ae9a60c5 100644 --- a/ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs +++ b/ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs @@ -33,14 +33,33 @@ namespace ICSharpCode.Decompiler.Tests.Semantics { // assign short names to the fake reflection types using C = Conversion; - using dynamic = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.Dynamic; - using nint = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.NInt; - using nuint = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.NUInt; - using Null = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.Null; + using dynamic = ConversionTest.Dynamic; + using nint = ConversionTest.NInt; + using nuint = ConversionTest.NUInt; [TestFixture, Parallelizable(ParallelScope.All)] public unsafe class ConversionTest { + /// + /// A reflection class used to represent null. + /// + public sealed class Null { } + + /// + /// A reflection class used to represent dynamic. + /// + public sealed class Dynamic { } + + /// + /// A reflection class used to represent nint. + /// + public sealed class NInt { } + + /// + /// A reflection class used to represent nuint. + /// + public sealed class NUInt { } + CSharpConversions conversions; ICompilation compilation; @@ -53,17 +72,37 @@ namespace ICSharpCode.Decompiler.Tests.Semantics conversions = new CSharpConversions(compilation); } + public class ReplaceSpecialTypesVisitor : TypeVisitor + { + public override IType VisitTypeDefinition(ITypeDefinition type) + { + switch (type.FullName) + { + case "ICSharpCode.Decompiler.Tests.Semantics.ConversionTest.Dynamic": + return SpecialType.Dynamic; + case "ICSharpCode.Decompiler.Tests.Semantics.ConversionTest.Null": + return SpecialType.NullType; + case "ICSharpCode.Decompiler.Tests.Semantics.ConversionTest.NInt": + return SpecialType.NInt; + case "ICSharpCode.Decompiler.Tests.Semantics.ConversionTest.NUInt": + return SpecialType.NUInt; + default: + return base.VisitTypeDefinition(type); + } + } + } + Conversion ImplicitConversion(Type from, Type to) { - IType from2 = compilation.FindType(from); - IType to2 = compilation.FindType(to); + IType from2 = compilation.FindType(from).AcceptVisitor(new ReplaceSpecialTypesVisitor()); + IType to2 = compilation.FindType(to).AcceptVisitor(new ReplaceSpecialTypesVisitor()); return conversions.ImplicitConversion(from2, to2); } Conversion ExplicitConversion(Type from, Type to) { - IType from2 = compilation.FindType(from); - IType to2 = compilation.FindType(to); + IType from2 = compilation.FindType(from).AcceptVisitor(new ReplaceSpecialTypesVisitor()); + IType to2 = compilation.FindType(to).AcceptVisitor(new ReplaceSpecialTypesVisitor()); return conversions.ExplicitConversion(from2, to2); } @@ -509,9 +548,9 @@ namespace ICSharpCode.Decompiler.Tests.Semantics bool IntegerLiteralConversion(object value, Type to) { - IType fromType = compilation.FindType(value.GetType()); + IType fromType = compilation.FindType(value.GetType()).AcceptVisitor(new ReplaceSpecialTypesVisitor()); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); - IType to2 = compilation.FindType(to); + IType to2 = compilation.FindType(to).AcceptVisitor(new ReplaceSpecialTypesVisitor()); return conversions.ImplicitConversion(crr, to2).IsValid; } @@ -587,18 +626,18 @@ namespace ICSharpCode.Decompiler.Tests.Semantics int BetterConversion(Type s, Type t1, Type t2) { - IType sType = compilation.FindType(s); - IType t1Type = compilation.FindType(t1); - IType t2Type = compilation.FindType(t2); + IType sType = compilation.FindType(s).AcceptVisitor(new ReplaceSpecialTypesVisitor()); + IType t1Type = compilation.FindType(t1).AcceptVisitor(new ReplaceSpecialTypesVisitor()); + IType t2Type = compilation.FindType(t2).AcceptVisitor(new ReplaceSpecialTypesVisitor()); return conversions.BetterConversion(sType, t1Type, t2Type); } int BetterConversion(object value, Type t1, Type t2) { - IType fromType = compilation.FindType(value.GetType()); + IType fromType = compilation.FindType(value.GetType()).AcceptVisitor(new ReplaceSpecialTypesVisitor()); ConstantResolveResult crr = new ConstantResolveResult(fromType, value); - IType t1Type = compilation.FindType(t1); - IType t2Type = compilation.FindType(t2); + IType t1Type = compilation.FindType(t1).AcceptVisitor(new ReplaceSpecialTypesVisitor()); + IType t2Type = compilation.FindType(t2).AcceptVisitor(new ReplaceSpecialTypesVisitor()); return conversions.BetterConversion(crr, t1Type, t2Type); } diff --git a/ICSharpCode.Decompiler.Tests/Semantics/ExplicitConversionTest.cs b/ICSharpCode.Decompiler.Tests/Semantics/ExplicitConversionTest.cs index 0abed50b6..70ea19baf 100644 --- a/ICSharpCode.Decompiler.Tests/Semantics/ExplicitConversionTest.cs +++ b/ICSharpCode.Decompiler.Tests/Semantics/ExplicitConversionTest.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; -using System.Linq; using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.Semantics; @@ -31,7 +30,7 @@ using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.Semantics { using C = Conversion; - using dynamic = ICSharpCode.Decompiler.TypeSystem.ReflectionHelper.Dynamic; + using dynamic = ConversionTest.Dynamic; [TestFixture, Parallelizable(ParallelScope.All)] public class ExplicitConversionsTest @@ -50,8 +49,8 @@ namespace ICSharpCode.Decompiler.Tests.Semantics Conversion ExplicitConversion(Type from, Type to) { - IType from2 = compilation.FindType(from); - IType to2 = compilation.FindType(to); + IType from2 = compilation.FindType(from).AcceptVisitor(new ConversionTest.ReplaceSpecialTypesVisitor()); + IType to2 = compilation.FindType(to).AcceptVisitor(new ConversionTest.ReplaceSpecialTypesVisitor()); return conversions.ExplicitConversion(from2, to2); } diff --git a/ICSharpCode.Decompiler.Tests/TypeSystem/ReflectionHelperTests.cs b/ICSharpCode.Decompiler.Tests/TypeSystem/ReflectionHelperTests.cs index 812d5ab83..9808804d9 100644 --- a/ICSharpCode.Decompiler.Tests/TypeSystem/ReflectionHelperTests.cs +++ b/ICSharpCode.Decompiler.Tests/TypeSystem/ReflectionHelperTests.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -71,20 +70,20 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem } [Test] - public void TestToTypeReferenceInnerClass() + public void TestFindTypeReflectionNameInnerClass() { Assert.That(compilation.FindType(typeof(Environment.SpecialFolder)).ReflectionName, Is.EqualTo("System.Environment+SpecialFolder")); } [Test] - public void TestToTypeReferenceUnboundGenericClass() + public void TestFindTypeReflectionNameUnboundGenericClass() { Assert.That(compilation.FindType(typeof(Action<>)).ReflectionName, Is.EqualTo("System.Action`1")); Assert.That(compilation.FindType(typeof(Action<,>)).ReflectionName, Is.EqualTo("System.Action`2")); } [Test] - public void TestToTypeReferenceBoundGenericClass() + public void TestFindTypeReflectionNameBoundGenericClass() { Assert.That(compilation.FindType(typeof(Action)).ReflectionName, Is.EqualTo("System.Action`1[[System.String]]")); Assert.That(compilation.FindType(typeof(Action)).ReflectionName, Is.EqualTo("System.Action`2[[System.Int32],[System.Int16]]")); @@ -92,69 +91,53 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem [Test] - public void TestToTypeReferenceNullableType() + public void TestFindTypeReflectionNameNullableType() { Assert.That(compilation.FindType(typeof(int?)).ReflectionName, Is.EqualTo("System.Nullable`1[[System.Int32]]")); } [Test] - public void TestToTypeReferenceInnerClassInUnboundGenericType() + public void TestFindTypeReflectionNameInnerClassInUnboundGenericType() { Assert.That(compilation.FindType(typeof(Dictionary<,>.ValueCollection)).ReflectionName, Is.EqualTo("System.Collections.Generic.Dictionary`2+ValueCollection")); } [Test] - public void TestToTypeReferenceInnerClassInBoundGenericType() + public void TestFindTypeReflectionNameInnerClassInBoundGenericType() { Assert.That(compilation.FindType(typeof(Dictionary.KeyCollection)).ReflectionName, Is.EqualTo("System.Collections.Generic.Dictionary`2+KeyCollection[[System.String],[System.Int32]]")); } [Test] - public void TestToTypeReferenceArrayType() + public void TestFindTypeReflectionNameArrayType() { Assert.That(compilation.FindType(typeof(int[])).ReflectionName, Is.EqualTo(typeof(int[]).FullName)); } [Test] - public void TestToTypeReferenceMultidimensionalArrayType() + public void TestFindTypeReflectionNameMultidimensionalArrayType() { Assert.That(compilation.FindType(typeof(int[,])).ReflectionName, Is.EqualTo(typeof(int[,]).FullName)); } [Test] - public void TestToTypeReferenceJaggedMultidimensionalArrayType() + public void TestFindTypeReflectionNameJaggedMultidimensionalArrayType() { Assert.That(compilation.FindType(typeof(int[,][,,])).ReflectionName, Is.EqualTo(typeof(int[,][,,]).FullName)); } [Test] - public void TestToTypeReferencePointerType() + public void TestFindTypeReflectionNamePointerType() { Assert.That(compilation.FindType(typeof(int*)).ReflectionName, Is.EqualTo(typeof(int*).FullName)); } [Test] - public void TestToTypeReferenceByReferenceType() + public void TestFindTypeReflectionNameByReferenceType() { Assert.That(compilation.FindType(typeof(int).MakeByRefType()).ReflectionName, Is.EqualTo(typeof(int).MakeByRefType().FullName)); } - [Test] - public void TestToTypeReferenceGenericType() - { - MethodInfo convertAllInfo = typeof(List<>).GetMethod("ConvertAll"); - ITypeReference parameterType = convertAllInfo.GetParameters()[0].ParameterType.ToTypeReference(); // Converter[[`0],[``0]] - // cannot resolve generic types without knowing the parent entity: - IType resolvedWithoutEntity = parameterType.Resolve(new SimpleTypeResolveContext(compilation)); - Assert.That(resolvedWithoutEntity.ReflectionName, Is.EqualTo("System.Converter`2[[`0],[``0]]")); - Assert.That(((ITypeParameter)((ParameterizedType)resolvedWithoutEntity).GetTypeArgument(0)).Owner, Is.Null); - // now try with parent entity: - IMethod convertAll = compilation.FindType(typeof(List<>)).GetMethods(m => m.Name == "ConvertAll").Single(); - IType resolvedWithEntity = parameterType.Resolve(new SimpleTypeResolveContext(convertAll)); - Assert.That(resolvedWithEntity.ReflectionName, Is.EqualTo("System.Converter`2[[`0],[``0]]")); - Assert.That(((ITypeParameter)((ParameterizedType)resolvedWithEntity).GetTypeArgument(0)).Owner, Is.SameAs(convertAll.DeclaringTypeDefinition)); - } - [Test] public void ParseReflectionName() { @@ -204,21 +187,21 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem public void ParseInvalidReflectionName2() { var context = new SimpleTypeResolveContext(compilation.MainModule); - Assert.Throws(() => ReflectionHelper.ParseReflectionName("`", context)); + Assert.That(ReflectionHelper.ParseReflectionName("`", context).ReflectionName, Is.EqualTo("`")); } [Test] public void ParseInvalidReflectionName3() { var context = new SimpleTypeResolveContext(compilation.MainModule); - Assert.Throws(() => ReflectionHelper.ParseReflectionName("``", context)); + Assert.That(ReflectionHelper.ParseReflectionName("``", context).ReflectionName, Is.EqualTo("``")); } [Test] public void ParseInvalidReflectionName4() { var context = new SimpleTypeResolveContext(compilation.MainModule); - Assert.Throws(() => ReflectionHelper.ParseReflectionName("System.Action`A", context)); + Assert.That(ReflectionHelper.ParseReflectionName("System.Action`A", context).ReflectionName, Is.EqualTo("System.Action`A")); } [Test] @@ -232,7 +215,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem public void ParseInvalidReflectionName5b() { var context = new SimpleTypeResolveContext(compilation.MainModule); - Assert.Throws(() => ReflectionHelper.ParseReflectionName("System.Environment+`", context)); + Assert.That(ReflectionHelper.ParseReflectionName("System.Environment+`", context).ReflectionName, Is.EqualTo("System.Environment+`")); } [Test] @@ -246,7 +229,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem public void ParseInvalidReflectionName7() { var context = new SimpleTypeResolveContext(compilation.MainModule); - Assert.Throws(() => ReflectionHelper.ParseReflectionName("System.Int32[`]", context)); + Assert.That(ReflectionHelper.ParseReflectionName("System.Int32[`]", context).ReflectionName, Is.EqualTo("System.Int32")); } [Test] diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/AstType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/AstType.cs index a8b8da53a..35b419f86 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/AstType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/AstType.cs @@ -16,12 +16,10 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; using System.Collections.Generic; using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; -using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.Syntax { @@ -60,11 +58,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { return other == null || other.IsNull; } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider) - { - return SpecialType.UnknownType; - } } #endregion @@ -102,11 +95,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return visitor.VisitPatternPlaceholder(this, child, data); } - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider) - { - throw new NotSupportedException(); - } - protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { return child.DoMatch(other, match); @@ -137,34 +125,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return st != null && st.Identifier == "var" && st.TypeArguments.Count == 0; } - /// - /// Create an ITypeReference for this AstType. - /// Uses the context (ancestors of this node) to determine the correct . - /// - /// - /// The resulting type reference will read the context information from the - /// : - /// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used. - /// For resolving simple names, the current namespace and usings from the CurrentUsingScope - /// (on CSharpTypeResolveContext only) is used. - /// - public ITypeReference ToTypeReference(InterningProvider interningProvider = null) - { - return ToTypeReference(GetNameLookupMode(), interningProvider); - } - - /// - /// Create an ITypeReference for this AstType. - /// - /// - /// The resulting type reference will read the context information from the - /// : - /// For resolving type parameters, the CurrentTypeDefinition/CurrentMember is used. - /// For resolving simple names, the current namespace and usings from the CurrentUsingScope - /// (on CSharpTypeResolveContext only) is used. - /// - public abstract ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null); - /// /// Gets the name lookup mode from the context (looking at the ancestors of this ). /// diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs index c042a2ca9..246183558 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs @@ -29,8 +29,6 @@ using System.Linq; using System.Text; using ICSharpCode.Decompiler.CSharp.OutputVisitor; -using ICSharpCode.Decompiler.CSharp.Resolver; -using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.Syntax { @@ -200,31 +198,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.HasRefSpecifier = true; return this; } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - if (interningProvider == null) - interningProvider = InterningProvider.Dummy; - ITypeReference t = this.BaseType.ToTypeReference(lookupMode, interningProvider); - if (this.HasNullableSpecifier) - { - t = interningProvider.Intern(NullableType.Create(t)); - } - int pointerRank = this.PointerRank; - for (int i = 0; i < pointerRank; i++) - { - t = interningProvider.Intern(new PointerTypeReference(t)); - } - foreach (var a in this.ArraySpecifiers.Reverse()) - { - t = interningProvider.Intern(new ArrayTypeReference(t, a.Dimensions)); - } - if (this.HasRefSpecifier) - { - t = interningProvider.Intern(new ByReferenceTypeReference(t)); - } - return t; - } } /// diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs index 96aee3ee9..b14d03466 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs @@ -24,11 +24,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using System; - -using ICSharpCode.Decompiler.CSharp.Resolver; -using ICSharpCode.Decompiler.TypeSystem; - namespace ICSharpCode.Decompiler.CSharp.Syntax { public class FunctionPointerAstType : AstType @@ -73,10 +68,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax && this.Parameters.DoMatch(o.Parameters, match) && this.ReturnType.DoMatch(o.ReturnType, match); } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - throw new NotImplementedException(); - } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/InvocationAstType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/InvocationAstType.cs index 5dddbfb56..99f601609 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/InvocationAstType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/InvocationAstType.cs @@ -16,13 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; -using System.Collections.Generic; -using System.Text; - -using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; -using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.Syntax { @@ -61,10 +55,5 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax && this.BaseType.DoMatch(o.BaseType, match) && this.Arguments.DoMatch(o.Arguments, match); } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - throw new NotImplementedException(); - } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs index 00abace78..a479bfbb4 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs @@ -26,10 +26,6 @@ using System.Collections.Generic; -using ICSharpCode.Decompiler.CSharp.Resolver; -using ICSharpCode.Decompiler.CSharp.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem; - namespace ICSharpCode.Decompiler.CSharp.Syntax { public class MemberType : AstType @@ -119,39 +115,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax && MatchString(this.MemberName, o.MemberName) && this.Target.DoMatch(o.Target, match) && this.TypeArguments.DoMatch(o.TypeArguments, match); } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - if (interningProvider == null) - interningProvider = InterningProvider.Dummy; - - TypeOrNamespaceReference t; - if (this.IsDoubleColon) - { - SimpleType st = this.Target as SimpleType; - if (st != null) - { - t = interningProvider.Intern(new AliasNamespaceReference(interningProvider.Intern(st.Identifier))); - } - else - { - t = null; - } - } - else - { - t = this.Target.ToTypeReference(lookupMode, interningProvider) as TypeOrNamespaceReference; - } - if (t == null) - return SpecialType.UnknownType; - var typeArguments = new List(); - foreach (var ta in this.TypeArguments) - { - typeArguments.Add(ta.ToTypeReference(lookupMode, interningProvider)); - } - string memberName = interningProvider.Intern(this.MemberName); - return interningProvider.Intern(new MemberTypeOrNamespaceReference(t, memberName, interningProvider.InternList(typeArguments), lookupMode)); - } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/PrimitiveType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/PrimitiveType.cs index a6f112542..d347e4421 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/PrimitiveType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/PrimitiveType.cs @@ -27,9 +27,7 @@ using System; using ICSharpCode.Decompiler.CSharp.OutputVisitor; -using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem.Implementation; namespace ICSharpCode.Decompiler.CSharp.Syntax { @@ -111,21 +109,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return Keyword; } - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - KnownTypeCode typeCode = GetTypeCodeForPrimitiveType(this.Keyword); - if (typeCode == KnownTypeCode.None) - { - if (this.Keyword == "__arglist") - return SpecialType.ArgList; - return new UnknownType(null, this.Keyword); - } - else - { - return KnownTypeReference.Get(typeCode); - } - } - public static KnownTypeCode GetTypeCodeForPrimitiveType(string keyword) { switch (keyword) diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs index 17a19e345..013b7836c 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs @@ -26,10 +26,6 @@ using System.Collections.Generic; -using ICSharpCode.Decompiler.CSharp.Resolver; -using ICSharpCode.Decompiler.CSharp.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem; - namespace ICSharpCode.Decompiler.CSharp.Syntax { public class SimpleType : AstType @@ -64,11 +60,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { return other == null || other.IsNull; } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider) - { - return SpecialType.UnknownType; - } } #endregion @@ -146,25 +137,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax SimpleType o = other as SimpleType; return o != null && MatchString(this.Identifier, o.Identifier) && this.TypeArguments.DoMatch(o.TypeArguments, match); } - - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - if (interningProvider == null) - interningProvider = InterningProvider.Dummy; - var typeArguments = new List(); - foreach (var ta in this.TypeArguments) - { - typeArguments.Add(ta.ToTypeReference(lookupMode, interningProvider)); - } - string identifier = interningProvider.Intern(this.Identifier); - if (typeArguments.Count == 0 && string.IsNullOrEmpty(identifier)) - { - // empty SimpleType is used for typeof(List<>). - return SpecialType.UnboundTypeArgument; - } - var t = new SimpleTypeOrNamespaceReference(identifier, interningProvider.InternList(typeArguments), lookupMode); - return interningProvider.Intern(t); - } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs index 16f5cd4aa..4fdaf0361 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs @@ -16,13 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; -using System.Collections.Immutable; -using System.Linq; - -using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; -using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.Syntax { @@ -49,14 +43,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax return visitor.VisitTupleType(this, data); } - public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null) - { - return new TupleTypeReference( - this.Elements.Select(e => e.Type.ToTypeReference(lookupMode, interningProvider)).ToImmutableArray(), - this.Elements.Select(e => e.Name).ToImmutableArray() - ); - } - protected internal override bool DoMatch(AstNode other, Match match) { return other is TupleAstType o && Elements.DoMatch(o.Elements, match); diff --git a/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs index 407bb98b5..de3416191 100644 --- a/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs +++ b/ICSharpCode.Decompiler/TypeSystem/ReflectionHelper.cs @@ -18,6 +18,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection.Metadata; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -29,31 +31,6 @@ namespace ICSharpCode.Decompiler.TypeSystem /// public static class ReflectionHelper { - /// - /// A reflection class used to represent null. - /// - public sealed class Null { } - - /// - /// A reflection class used to represent dynamic. - /// - public sealed class Dynamic { } - - /// - /// A reflection class used to represent nint. - /// - public sealed class NInt { } - - /// - /// A reflection class used to represent nuint. - /// - public sealed class NUInt { } - - /// - /// A reflection class used to represent an unbound type argument. - /// - public sealed class UnboundTypeArgument { } - #region ICompilation.FindType /// /// Retrieves the specified type in this compilation. @@ -65,7 +42,7 @@ namespace ICSharpCode.Decompiler.TypeSystem /// public static IType FindType(this ICompilation compilation, Type type) { - return type.ToTypeReference().Resolve(new SimpleTypeResolveContext(compilation)); + return ParseReflectionName(type.AssemblyQualifiedName, new SimpleTypeResolveContext(compilation)); } public static IType FindType(this ICompilation compilation, StackType stackType, Sign sign = Sign.None) @@ -82,88 +59,6 @@ namespace ICSharpCode.Decompiler.TypeSystem } #endregion - #region Type.ToTypeReference() - /// - /// Creates a reference to the specified type. - /// - /// The type to be converted. - /// Returns the type reference. - /// - /// If the type is open (contains type parameters '`0' or '``0'), - /// an with the appropriate CurrentTypeDefinition/CurrentMember is required - /// to resolve the type reference. - /// For closed types, the root type resolve context for the compilation is sufficient. - /// - public static ITypeReference ToTypeReference(this Type type) - { - if (type == null) - return SpecialType.UnknownType; - if (type.IsGenericType && !type.IsGenericTypeDefinition) - { - ITypeReference def = ToTypeReference(type.GetGenericTypeDefinition()); - Type[] arguments = type.GetGenericArguments(); - ITypeReference[] args = new ITypeReference[arguments.Length]; - bool allUnbound = true; - for (int i = 0; i < arguments.Length; i++) - { - args[i] = ToTypeReference(arguments[i]); - allUnbound &= args[i].Equals(SpecialType.UnboundTypeArgument); - } - if (allUnbound) - return def; - else - return new ParameterizedTypeReference(def, args); - } - else if (type.IsArray) - { - return new ArrayTypeReference(ToTypeReference(type.GetElementType()), type.GetArrayRank()); - } - else if (type.IsPointer) - { - return new PointerTypeReference(ToTypeReference(type.GetElementType())); - } - else if (type.IsByRef) - { - return new ByReferenceTypeReference(ToTypeReference(type.GetElementType())); - } - else if (type.IsGenericParameter) - { - if (type.DeclaringMethod != null) - { - return TypeParameterReference.Create(SymbolKind.Method, type.GenericParameterPosition); - } - else - { - return TypeParameterReference.Create(SymbolKind.TypeDefinition, type.GenericParameterPosition); - } - } - else if (type.DeclaringType != null) - { - if (type == typeof(Dynamic)) - return SpecialType.Dynamic; - else if (type == typeof(NInt)) - return SpecialType.NInt; - else if (type == typeof(NUInt)) - return SpecialType.NUInt; - else if (type == typeof(Null)) - return SpecialType.NullType; - else if (type == typeof(UnboundTypeArgument)) - return SpecialType.UnboundTypeArgument; - ITypeReference baseTypeRef = ToTypeReference(type.DeclaringType); - int typeParameterCount; - string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); - return new NestedTypeReference(baseTypeRef, name, typeParameterCount); - } - else - { - IModuleReference assemblyReference = new DefaultAssemblyReference(type.Assembly.FullName); - int typeParameterCount; - string name = SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); - return new GetClassTypeReference(assemblyReference, type.Namespace, name, typeParameterCount); - } - } - #endregion - #region SplitTypeParameterCountFromReflectionName /// /// Removes the ` with type parameter count from the reflection name. @@ -214,16 +109,6 @@ namespace ICSharpCode.Decompiler.TypeSystem return compilation.FindType((KnownTypeCode)typeCode); } - /// - /// Creates a reference to the specified type. - /// - /// The type to be converted. - /// Returns the type reference. - public static ITypeReference ToTypeReference(this TypeCode typeCode) - { - return KnownTypeReference.Get((KnownTypeCode)typeCode); - } - /// /// Gets the type code for the specified type, or TypeCode.Empty if none of the other type codes match. /// @@ -264,11 +149,112 @@ namespace ICSharpCode.Decompiler.TypeSystem { if (reflectionTypeName == null) throw new ArgumentNullException(nameof(reflectionTypeName)); - int pos = 0; - IType r = ParseReflectionName(reflectionTypeName, ref pos).Resolve(resolveContext); - if (pos < reflectionTypeName.Length) - throw new ReflectionNameParseException(pos, "Expected end of type name"); - return r; + if (!TypeName.TryParse(reflectionTypeName.AsSpan(), out var result)) + { + throw new ReflectionNameParseException(0, "Invalid type name: " + reflectionTypeName); + } + return ResolveTypeName(result, resolveContext); + } + + private static IType ResolveTypeName(TypeName result, ITypeResolveContext resolveContext) + { + if (result.IsArray) + { + return new ArrayType( + resolveContext.Compilation, + ResolveTypeName(result.GetElementType(), resolveContext), + result.GetArrayRank() + ); + } + else if (result.IsByRef) + { + return new ByReferenceType( + ResolveTypeName(result.GetElementType(), resolveContext) + ); + } + else if (result.IsConstructedGenericType) + { + IType genericType = ResolveTypeName(result.GetGenericTypeDefinition(), resolveContext); + var genericArgs = result.GetGenericArguments(); + if (genericType.TypeParameterCount == 0) + { + return genericType; + } + + IType[] resolvedTypes = new IType[genericType.TypeParameterCount]; + for (int i = 0; i < genericArgs.Length; i++) + { + if (i < genericArgs.Length) + resolvedTypes[i] = ResolveTypeName(genericArgs[i], resolveContext); + else + resolvedTypes[i] = SpecialType.UnknownType; + } + return new ParameterizedType(genericType, resolvedTypes); + } + else if (result.IsNested) + { + var declaringType = ResolveTypeName(result.DeclaringType, resolveContext).GetDefinition(); + var plainName = SplitTypeParameterCountFromReflectionName(result.Name, out int tpc); + if (declaringType != null) + { + foreach (var type in declaringType.NestedTypes) + { + if (type.Name == plainName && type.TypeParameterCount == tpc + declaringType.TypeParameterCount) + return type; + } + } + return new UnknownType(new FullTypeName(result.FullName)); + } + else if (result.IsPointer) + { + return new PointerType( + ResolveTypeName(result.GetElementType(), resolveContext) + ); + } + else + { + Debug.Assert(result.IsSimple); + if (result.FullName.Length > 1 && result.FullName[0] == '`') + { + if (result.FullName.Length > 2 && result.FullName[1] == '`') + { + if (int.TryParse(result.FullName.Substring(2), out int index)) + { + if (resolveContext.CurrentMember is IMethod m && index < m.TypeParameters.Count) + { + return m.TypeParameters[index]; + } + return DummyTypeParameter.GetMethodTypeParameter(index); + } + } + else if (int.TryParse(result.FullName.Substring(1), out int index)) + { + if (resolveContext.CurrentTypeDefinition != null && index < resolveContext.CurrentTypeDefinition.TypeParameterCount) + { + return resolveContext.CurrentTypeDefinition.TypeParameters[index]; + } + return DummyTypeParameter.GetClassTypeParameter(index); + } + } + var topLevelTypeName = new TopLevelTypeName(result.FullName); + if (result.AssemblyName != null) + { + var module = resolveContext.Compilation.FindModuleByAssemblyNameInfo(result.AssemblyName); + if (module != null) + { + return (IType)module.GetTypeDefinition(topLevelTypeName) ?? new UnknownType(topLevelTypeName); + } + } + + foreach (var module in resolveContext.Compilation.Modules) + { + var type = module.GetTypeDefinition(topLevelTypeName); + if (type != null) + return type; + } + + return new UnknownType(topLevelTypeName); + } } static bool IsReflectionNameSpecialCharacter(char c) diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs index c983e354b..1a4b11501 100644 --- a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs +++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Semantics; @@ -814,6 +815,25 @@ namespace ICSharpCode.Decompiler.TypeSystem return null; } + public static IModule FindModuleByAssemblyNameInfo(this ICompilation compilation, AssemblyNameInfo assemblyName) + { + foreach (var module in compilation.Modules) + { + if (string.Equals(module.FullAssemblyName, assemblyName.FullName, StringComparison.OrdinalIgnoreCase)) + { + return module; + } + } + foreach (var module in compilation.Modules) + { + if (string.Equals(module.Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase)) + { + return module; + } + } + return null; + } + /// /// When given a generic type definition, returns the self-parameterized type /// (i.e. the type of "this" within the type definition).