From c9e3790adc9705be0a553cd9481037a365adfa43 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 2 Aug 2025 11:00:31 +0200 Subject: [PATCH] Remove UnresolvedUsingScope --- .../CSharp/CSharpDecompiler.cs | 56 ++++-- ICSharpCode.Decompiler/CSharp/CallBuilder.cs | 1 - .../CSharp/ExpressionBuilder.cs | 2 +- .../Transforms/IntroduceExtensionMethods.cs | 34 ++-- .../Transforms/IntroduceUsingDeclarations.cs | 86 ++++----- .../CSharp/TypeSystem/ResolvedUsingScope.cs | 143 +++------------ .../CSharp/TypeSystem/UsingScope.cs | 167 ------------------ ICSharpCode.Decompiler/DecompileRun.cs | 30 +--- .../ICSharpCode.Decompiler.csproj | 1 - .../IL/Transforms/IILTransform.cs | 2 +- .../TypeSystem/TypeSystemExtensions.cs | 3 +- 11 files changed, 130 insertions(+), 395 deletions(-) delete mode 100644 ICSharpCode.Decompiler/CSharp/TypeSystem/UsingScope.cs diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index ceec1103e..fc96edc93 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; @@ -30,6 +31,7 @@ using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Transforms; +using ICSharpCode.Decompiler.CSharp.TypeSystem; using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Documentation; @@ -518,11 +520,28 @@ namespace ICSharpCode.Decompiler.CSharp } } - DecompileRun CreateDecompileRun() + DecompileRun CreateDecompileRun(HashSet namespaces) { - return new DecompileRun(settings) { + List resolvedNamespaces = new List(); + foreach (var ns in namespaces) + { + var resolvedNamespace = typeSystem.GetNamespaceByFullName(ns); + if (resolvedNamespace != null) + { + resolvedNamespaces.Add(resolvedNamespace); + } + } + + ResolvedUsingScope usingScope = new ResolvedUsingScope( + new CSharpTypeResolveContext(typeSystem.MainModule), + typeSystem.RootNamespace, + resolvedNamespaces.ToImmutableArray() + ); + + return new DecompileRun(settings, usingScope) { DocumentationProvider = DocumentationProvider ?? CreateDefaultDocumentationProvider(), - CancellationToken = CancellationToken + CancellationToken = CancellationToken, + Namespaces = namespaces }; } @@ -554,9 +573,10 @@ namespace ICSharpCode.Decompiler.CSharp public SyntaxTree DecompileModuleAndAssemblyAttributes() { var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule); - DecompileRun decompileRun = CreateDecompileRun(); + var namespaces = new HashSet(); syntaxTree = new SyntaxTree(); - RequiredNamespaceCollector.CollectAttributeNamespaces(module, decompileRun.Namespaces); + RequiredNamespaceCollector.CollectAttributeNamespaces(module, namespaces); + DecompileRun decompileRun = CreateDecompileRun(namespaces); DoDecompileModuleAndAssemblyAttributes(decompileRun, decompilationContext, syntaxTree); RunTransforms(syntaxTree, decompileRun, decompilationContext); return syntaxTree; @@ -640,9 +660,10 @@ namespace ICSharpCode.Decompiler.CSharp public SyntaxTree DecompileWholeModuleAsSingleFile(bool sortTypes) { var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule); - var decompileRun = CreateDecompileRun(); syntaxTree = new SyntaxTree(); - RequiredNamespaceCollector.CollectNamespaces(module, decompileRun.Namespaces); + var namespaces = new HashSet(); + RequiredNamespaceCollector.CollectNamespaces(module, namespaces); + var decompileRun = CreateDecompileRun(namespaces); DoDecompileModuleAndAssemblyAttributes(decompileRun, decompilationContext, syntaxTree); var typeDefs = metadata.GetTopLevelTypeDefinitions(); if (sortTypes) @@ -662,8 +683,9 @@ namespace ICSharpCode.Decompiler.CSharp /// public ILTransformContext CreateILTransformContext(ILFunction function) { - var decompileRun = CreateDecompileRun(); - RequiredNamespaceCollector.CollectNamespaces(function.Method, module, decompileRun.Namespaces); + var namespaces = new HashSet(); + RequiredNamespaceCollector.CollectNamespaces(function.Method, module, namespaces); + var decompileRun = CreateDecompileRun(namespaces); return new ILTransformContext(function, typeSystem, DebugInfoProvider, settings) { CancellationToken = CancellationToken, DecompileRun = decompileRun @@ -907,17 +929,17 @@ namespace ICSharpCode.Decompiler.CSharp if (types == null) throw new ArgumentNullException(nameof(types)); var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule); - var decompileRun = CreateDecompileRun(); syntaxTree = new SyntaxTree(); - + var namespaces = new HashSet(); foreach (var type in types) { CancellationToken.ThrowIfCancellationRequested(); if (type.IsNil) throw new ArgumentException("types contains null element"); - RequiredNamespaceCollector.CollectNamespaces(type, module, decompileRun.Namespaces); + RequiredNamespaceCollector.CollectNamespaces(type, module, namespaces); } + var decompileRun = CreateDecompileRun(namespaces); DoDecompileTypes(types, decompileRun, decompilationContext, syntaxTree); RunTransforms(syntaxTree, decompileRun, decompilationContext); return syntaxTree; @@ -949,9 +971,10 @@ namespace ICSharpCode.Decompiler.CSharp if (type.ParentModule != typeSystem.MainModule) throw new NotSupportedException($"Type {fullTypeName} was not found in the module being decompiled, but only in {type.ParentModule.Name}"); var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainModule); - var decompileRun = CreateDecompileRun(); + var namespaces = new HashSet(); syntaxTree = new SyntaxTree(); - RequiredNamespaceCollector.CollectNamespaces(type.MetadataToken, module, decompileRun.Namespaces); + RequiredNamespaceCollector.CollectNamespaces(type.MetadataToken, module, namespaces); + var decompileRun = CreateDecompileRun(namespaces); DoDecompileTypes(new[] { (TypeDefinitionHandle)type.MetadataToken }, decompileRun, decompilationContext, syntaxTree); RunTransforms(syntaxTree, decompileRun, decompilationContext); return syntaxTree; @@ -984,13 +1007,14 @@ namespace ICSharpCode.Decompiler.CSharp if (definitions == null) throw new ArgumentNullException(nameof(definitions)); syntaxTree = new SyntaxTree(); - var decompileRun = CreateDecompileRun(); + var namespaces = new HashSet(); foreach (var entity in definitions) { if (entity.IsNil) throw new ArgumentException("definitions contains null element"); - RequiredNamespaceCollector.CollectNamespaces(entity, module, decompileRun.Namespaces); + RequiredNamespaceCollector.CollectNamespaces(entity, module, namespaces); } + var decompileRun = CreateDecompileRun(namespaces); bool first = true; ITypeDefinition parentTypeDef = null; diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index f57051e05..2ff1ce4d1 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -2051,7 +2051,6 @@ namespace ICSharpCode.Decompiler.CSharp if (isExtensionMethodReference) { - var resolver = this.resolver.WithCurrentUsingScope(this.expressionBuilder.statementBuilder.decompileRun.UsingScope.Resolve(this.resolver.Compilation)); result = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult; if (result == null) return false; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index d55839037..3f5427a12 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.CSharp this.compilation = decompilationContext.Compilation; this.resolver = new CSharpResolver(new CSharpTypeResolveContext( compilation.MainModule, - decompileRun.UsingScope.Resolve(compilation), + decompileRun.UsingScope, decompilationContext.CurrentTypeDefinition, decompilationContext.CurrentMember )); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs index 4aa48b9f9..2ec0fefc2 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs @@ -42,63 +42,53 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms { this.context = context; this.conversions = CSharpConversions.Get(context.TypeSystem); - InitializeContext(rootNode.Annotation()); + InitializeContext(rootNode.Annotation()); rootNode.AcceptVisitor(this); } - Stack resolveContextStack = new Stack(); - - void InitializeContext(UsingScope usingScope) + void InitializeContext(ResolvedUsingScope usingScope) { - this.resolveContextStack = new Stack(); if (!string.IsNullOrEmpty(context.CurrentTypeDefinition?.Namespace)) { foreach (string ns in context.CurrentTypeDefinition.Namespace.Split('.')) { - usingScope = new UsingScope(usingScope, ns); + usingScope = usingScope.WithNestedNamespace(ns); } } - var currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainModule, usingScope.Resolve(context.TypeSystem), context.CurrentTypeDefinition); - this.resolveContextStack.Push(currentContext); + var currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainModule, usingScope, context.CurrentTypeDefinition); this.resolver = new CSharpResolver(currentContext); } public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) { - var previousContext = resolveContextStack.Peek(); - var usingScope = previousContext.CurrentUsingScope.UnresolvedUsingScope; + var usingScope = resolver.CurrentUsingScope; foreach (string ident in namespaceDeclaration.Identifiers) { - usingScope = new UsingScope(usingScope, ident); + usingScope = usingScope.WithNestedNamespace(ident); } - var currentContext = new CSharpTypeResolveContext(previousContext.CurrentModule, usingScope.Resolve(previousContext.Compilation)); - resolveContextStack.Push(currentContext); + var previousResolver = this.resolver; try { - this.resolver = new CSharpResolver(currentContext); + this.resolver = this.resolver.WithCurrentUsingScope(usingScope); base.VisitNamespaceDeclaration(namespaceDeclaration); } finally { - this.resolver = new CSharpResolver(previousContext); - resolveContextStack.Pop(); + this.resolver = previousResolver; } } public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) { - var previousContext = resolveContextStack.Peek(); - var currentContext = previousContext.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); - resolveContextStack.Push(currentContext); + var previousResolver = this.resolver; + this.resolver = resolver.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); try { - this.resolver = new CSharpResolver(currentContext); base.VisitTypeDeclaration(typeDeclaration); } finally { - this.resolver = new CSharpResolver(previousContext); - resolveContextStack.Pop(); + this.resolver = previousResolver; } } diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs index 1b4523399..4e712379a 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -42,8 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms var requiredImports = new FindRequiredImports(context); rootNode.AcceptVisitor(requiredImports); - var usingScope = new UsingScope(); - rootNode.AddAnnotation(usingScope); + List resolvedNamespaces = new List(); if (context.Settings.UsingDeclarations) { @@ -64,12 +64,22 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms { nsType = new MemberType { Target = nsType, MemberName = parts[i] }; } - if (nsType.ToTypeReference(NameLookupMode.TypeInUsingDeclaration) is TypeOrNamespaceReference reference) - usingScope.Usings.Add(reference); + var resolvedNamespace = context.TypeSystem.GetNamespaceByFullName(ns); + if (resolvedNamespace != null) + { + resolvedNamespaces.Add(resolvedNamespace); + } rootNode.InsertChildAfter(insertionPoint, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole); } } + var usingScope = new ResolvedUsingScope( + new CSharpTypeResolveContext(context.TypeSystem.MainModule), + context.TypeSystem.RootNamespace, + resolvedNamespaces.ToImmutableArray() + ); + rootNode.AddAnnotation(usingScope); + // verify that the SimpleTypes refer to the correct type (no ambiguities) rootNode.AcceptVisitor(new FullyQualifyAmbiguousTypeNamesVisitor(context, usingScope)); } @@ -173,41 +183,35 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms sealed class FullyQualifyAmbiguousTypeNamesVisitor : DepthFirstAstVisitor { - readonly Stack context; readonly bool ignoreUsingScope; readonly DecompilerSettings settings; + CSharpResolver resolver; TypeSystemAstBuilder astBuilder; - public FullyQualifyAmbiguousTypeNamesVisitor(TransformContext context, UsingScope usingScope) + public FullyQualifyAmbiguousTypeNamesVisitor(TransformContext context, ResolvedUsingScope usingScope) { this.ignoreUsingScope = !context.Settings.UsingDeclarations; this.settings = context.Settings; + this.resolver = new CSharpResolver(new CSharpTypeResolveContext(context.TypeSystem.MainModule)); - CSharpTypeResolveContext currentContext; - if (ignoreUsingScope) - { - currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainModule); - } - else + if (!ignoreUsingScope) { - this.context = new Stack(); if (!string.IsNullOrEmpty(context.CurrentTypeDefinition?.Namespace)) { foreach (string ns in context.CurrentTypeDefinition.Namespace.Split('.')) { - usingScope = new UsingScope(usingScope, ns); + usingScope = usingScope.WithNestedNamespace(ns); } } - currentContext = new CSharpTypeResolveContext(context.TypeSystem.MainModule, usingScope.Resolve(context.TypeSystem), context.CurrentTypeDefinition); - this.context.Push(currentContext); + this.resolver = this.resolver.WithCurrentUsingScope(usingScope) + .WithCurrentTypeDefinition(context.CurrentTypeDefinition); } - this.astBuilder = CreateAstBuilder(currentContext); + this.astBuilder = CreateAstBuilder(resolver); } - TypeSystemAstBuilder CreateAstBuilder(CSharpTypeResolveContext context, IL.ILFunction function = null) + TypeSystemAstBuilder CreateAstBuilder(CSharpResolver resolver, IL.ILFunction function = null) { - CSharpResolver resolver = new CSharpResolver(context); if (function != null) { var variables = new Dictionary(); @@ -234,23 +238,23 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms base.VisitNamespaceDeclaration(namespaceDeclaration); return; } - var previousContext = context.Peek(); - var usingScope = previousContext.CurrentUsingScope.UnresolvedUsingScope; + var previousResolver = resolver; + var previousAstBuilder = astBuilder; + var usingScope = resolver.CurrentUsingScope; foreach (string ident in namespaceDeclaration.Identifiers) { - usingScope = new UsingScope(usingScope, ident); + usingScope = usingScope.WithNestedNamespace(ident); } - var currentContext = new CSharpTypeResolveContext(previousContext.CurrentModule, usingScope.Resolve(previousContext.Compilation)); - context.Push(currentContext); + resolver = resolver.WithCurrentUsingScope(usingScope); try { - astBuilder = CreateAstBuilder(currentContext); + astBuilder = CreateAstBuilder(resolver); base.VisitNamespaceDeclaration(namespaceDeclaration); } finally { - astBuilder = CreateAstBuilder(previousContext); - context.Pop(); + astBuilder = previousAstBuilder; + resolver = previousResolver; } } @@ -261,18 +265,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms base.VisitTypeDeclaration(typeDeclaration); return; } - var previousContext = context.Peek(); - var currentContext = previousContext.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); - context.Push(currentContext); + var previousResolver = resolver; + var previousAstBuilder = astBuilder; + resolver = resolver.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); try { - astBuilder = CreateAstBuilder(currentContext); + astBuilder = CreateAstBuilder(resolver); base.VisitTypeDeclaration(typeDeclaration); } finally { - astBuilder = CreateAstBuilder(previousContext); - context.Pop(); + astBuilder = previousAstBuilder; + resolver = previousResolver; } } @@ -310,27 +314,27 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } if (entityDeclaration.GetSymbol() is IMethod method) { - var previousContext = context.Peek(); - CSharpTypeResolveContext currentContext; + var previousResolver = resolver; + var previousAstBuilder = astBuilder; if (CSharpDecompiler.IsWindowsFormsInitializeComponentMethod(method)) { - currentContext = new CSharpTypeResolveContext(previousContext.CurrentModule); + var currentContext = new CSharpTypeResolveContext(previousResolver.Compilation.MainModule); + resolver = new CSharpResolver(currentContext); } else { - currentContext = previousContext.WithCurrentMember(method); + resolver = resolver.WithCurrentMember(method); } - context.Push(currentContext); try { var function = entityDeclaration.Annotation(); - astBuilder = CreateAstBuilder(currentContext, function); + astBuilder = CreateAstBuilder(resolver, function); baseCall(entityDeclaration); } finally { - astBuilder = CreateAstBuilder(previousContext); - context.Pop(); + resolver = previousResolver; + astBuilder = previousAstBuilder; } } else diff --git a/ICSharpCode.Decompiler/CSharp/TypeSystem/ResolvedUsingScope.cs b/ICSharpCode.Decompiler/CSharp/TypeSystem/ResolvedUsingScope.cs index c6e10cfbd..7ad08283b 100644 --- a/ICSharpCode.Decompiler/CSharp/TypeSystem/ResolvedUsingScope.cs +++ b/ICSharpCode.Decompiler/CSharp/TypeSystem/ResolvedUsingScope.cs @@ -19,153 +19,60 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; +using System.Collections.Immutable; -using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.Semantics; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; +#nullable enable + namespace ICSharpCode.Decompiler.CSharp.TypeSystem { /// - /// Resolved version of using scope. + /// Represents a scope that contains "using" statements. + /// This is either the mo itself, or a namespace declaration. /// public class ResolvedUsingScope { readonly CSharpTypeResolveContext parentContext; - readonly UsingScope usingScope; internal readonly ConcurrentDictionary ResolveCache = new ConcurrentDictionary(); - internal List> AllExtensionMethods; + internal List>? AllExtensionMethods; - public ResolvedUsingScope(CSharpTypeResolveContext context, UsingScope usingScope) + public ResolvedUsingScope(CSharpTypeResolveContext context, INamespace @namespace, ImmutableArray usings) { - if (context == null) - throw new ArgumentNullException(nameof(context)); - if (usingScope == null) - throw new ArgumentNullException(nameof(usingScope)); - this.parentContext = context; - this.usingScope = usingScope; - if (usingScope.Parent != null) - { - if (context.CurrentUsingScope == null) - throw new InvalidOperationException(); - } - else - { - if (context.CurrentUsingScope != null) - throw new InvalidOperationException(); - } + this.parentContext = context ?? throw new ArgumentNullException(nameof(context)); + this.Usings = usings; + this.Namespace = @namespace ?? throw new ArgumentNullException(nameof(@namespace)); } - public UsingScope UnresolvedUsingScope { - get { return usingScope; } - } - - INamespace @namespace; - - public INamespace Namespace { - get { - INamespace result = LazyInit.VolatileRead(ref this.@namespace); - if (result != null) - { - return result; - } - else - { - if (parentContext.CurrentUsingScope != null) - { - result = parentContext.CurrentUsingScope.Namespace.GetChildNamespace(usingScope.ShortNamespaceName); - if (result == null) - result = new DummyNamespace(parentContext.CurrentUsingScope.Namespace, usingScope.ShortNamespaceName); - } - else - { - result = parentContext.Compilation.RootNamespace; - } - Debug.Assert(result != null); - return LazyInit.GetOrSet(ref this.@namespace, result); - } - } - } + public INamespace Namespace { get; } public ResolvedUsingScope Parent { get { return parentContext.CurrentUsingScope; } } - IList usings; - - public IList Usings { - get { - var result = LazyInit.VolatileRead(ref this.usings); - if (result != null) - { - return result; - } - else - { - result = new List(); - CSharpResolver resolver = new CSharpResolver(parentContext.WithUsingScope(this)); - foreach (var u in usingScope.Usings) - { - INamespace ns = u.ResolveNamespace(resolver); - if (ns != null && !result.Contains(ns)) - result.Add(ns); - } - return LazyInit.GetOrSet(ref this.usings, new ReadOnlyCollection(result)); - } - } - } + public ImmutableArray Usings { get; } - IList> usingAliases; - - public IList> UsingAliases { - get { - var result = LazyInit.VolatileRead(ref this.usingAliases); - if (result != null) - { - return result; - } - else - { - CSharpResolver resolver = new CSharpResolver(parentContext.WithUsingScope(this)); - result = new KeyValuePair[usingScope.UsingAliases.Count]; - for (int i = 0; i < result.Count; i++) - { - var rr = usingScope.UsingAliases[i].Value.Resolve(resolver); - if (rr is TypeResolveResult) - { - rr = new AliasTypeResolveResult(usingScope.UsingAliases[i].Key, (TypeResolveResult)rr); - } - else if (rr is NamespaceResolveResult) - { - rr = new AliasNamespaceResolveResult(usingScope.UsingAliases[i].Key, (NamespaceResolveResult)rr); - } - result[i] = new KeyValuePair( - usingScope.UsingAliases[i].Key, - rr - ); - } - return LazyInit.GetOrSet(ref this.usingAliases, result); - } - } - } + public IReadOnlyList> UsingAliases => []; - public IList ExternAliases { - get { return usingScope.ExternAliases; } - } + public IReadOnlyList ExternAliases => []; /// /// Gets whether this using scope has an alias (either using or extern) /// with the specified name. /// - public bool HasAlias(string identifier) + public bool HasAlias(string identifier) => false; + + internal ResolvedUsingScope WithNestedNamespace(string simpleName) { - return usingScope.HasAlias(identifier); + var ns = Namespace.GetChildNamespace(simpleName) ?? new DummyNamespace(Namespace, simpleName); + return new ResolvedUsingScope( + parentContext.WithUsingScope(this), + ns, + []); } sealed class DummyNamespace : INamespace @@ -179,7 +86,7 @@ namespace ICSharpCode.Decompiler.CSharp.TypeSystem this.name = name; } - public string ExternAlias { get; set; } + string INamespace.ExternAlias => ""; string INamespace.FullName { get { return NamespaceDeclaration.BuildQualifiedName(parentNamespace.FullName, name); } @@ -213,12 +120,12 @@ namespace ICSharpCode.Decompiler.CSharp.TypeSystem get { return parentNamespace.Compilation; } } - INamespace INamespace.GetChildNamespace(string name) + INamespace? INamespace.GetChildNamespace(string name) { return null; } - ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) + ITypeDefinition? INamespace.GetTypeDefinition(string name, int typeParameterCount) { return null; } diff --git a/ICSharpCode.Decompiler/CSharp/TypeSystem/UsingScope.cs b/ICSharpCode.Decompiler/CSharp/TypeSystem/UsingScope.cs deleted file mode 100644 index 05ef4e6eb..000000000 --- a/ICSharpCode.Decompiler/CSharp/TypeSystem/UsingScope.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// 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.Syntax; -using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem.Implementation; -using ICSharpCode.Decompiler.Util; - -namespace ICSharpCode.Decompiler.CSharp.TypeSystem -{ - /// - /// Represents a scope that contains "using" statements. - /// This is either the file itself, or a namespace declaration. - /// - [Serializable] - public class UsingScope : AbstractFreezable - { - readonly UsingScope parent; - string shortName = ""; - IList usings; - IList> usingAliases; - IList externAliases; - - protected override void FreezeInternal() - { - usings = FreezableHelper.FreezeList(usings); - usingAliases = FreezableHelper.FreezeList(usingAliases); - externAliases = FreezableHelper.FreezeList(externAliases); - - // In current model (no child scopes), it makes sense to freeze the parent as well - // to ensure the whole lookup chain is immutable. - if (parent != null) - parent.Freeze(); - - base.FreezeInternal(); - } - - /// - /// Creates a new root using scope. - /// - public UsingScope() - { - } - - /// - /// Creates a new nested using scope. - /// - /// The parent using scope. - /// The short namespace name. - public UsingScope(UsingScope parent, string shortName) - { - if (parent == null) - throw new ArgumentNullException(nameof(parent)); - if (shortName == null) - throw new ArgumentNullException(nameof(shortName)); - this.parent = parent; - this.shortName = shortName; - } - - public UsingScope Parent { - get { return parent; } - } - - public string ShortNamespaceName { - get { - return shortName; - } - } - - public string NamespaceName { - get { - if (parent != null) - return NamespaceDeclaration.BuildQualifiedName(parent.NamespaceName, shortName); - else - return shortName; - } - // set { - // if (value == null) - // throw new ArgumentNullException("NamespaceName"); - // FreezableHelper.ThrowIfFrozen(this); - // namespaceName = value; - // } - } - - public IList Usings { - get { - if (usings == null) - usings = new List(); - return usings; - } - } - - public IList> UsingAliases { - get { - if (usingAliases == null) - usingAliases = new List>(); - return usingAliases; - } - } - - public IList ExternAliases { - get { - if (externAliases == null) - externAliases = new List(); - return externAliases; - } - } - - // public IList ChildScopes { - // get { - // if (childScopes == null) - // childScopes = new List(); - // return childScopes; - // } - // } - - /// - /// Gets whether this using scope has an alias (either using or extern) - /// with the specified name. - /// - public bool HasAlias(string identifier) - { - if (usingAliases != null) - { - foreach (var pair in usingAliases) - { - if (pair.Key == identifier) - return true; - } - } - return externAliases != null && externAliases.Contains(identifier); - } - - /// - /// Resolves the namespace represented by this using scope. - /// - public ResolvedUsingScope Resolve(ICompilation compilation) - { - CacheManager cache = compilation.CacheManager; - ResolvedUsingScope resolved = cache.GetShared(this) as ResolvedUsingScope; - if (resolved == null) - { - var csContext = new CSharpTypeResolveContext(compilation.MainModule, parent != null ? parent.Resolve(compilation) : null); - resolved = (ResolvedUsingScope)cache.GetOrAddShared(this, new ResolvedUsingScope(csContext, this)); - } - return resolved; - } - } -} diff --git a/ICSharpCode.Decompiler/DecompileRun.cs b/ICSharpCode.Decompiler/DecompileRun.cs index 8a1a31a90..edfdca568 100644 --- a/ICSharpCode.Decompiler/DecompileRun.cs +++ b/ICSharpCode.Decompiler/DecompileRun.cs @@ -21,7 +21,6 @@ using System.Collections.Generic; using System.Threading; using ICSharpCode.Decompiler.CSharp; -using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.TypeSystem; @@ -30,7 +29,7 @@ namespace ICSharpCode.Decompiler internal class DecompileRun { public HashSet DefinedSymbols { get; } = new HashSet(); - public HashSet Namespaces { get; } = new HashSet(); + public HashSet Namespaces { get; set; } public CancellationToken CancellationToken { get; set; } public DecompilerSettings Settings { get; } public IDocumentationProvider DocumentationProvider { get; set; } @@ -38,33 +37,12 @@ namespace ICSharpCode.Decompiler public Dictionary TypeHierarchyIsKnown { get; } = new(); - Lazy usingScope => - new Lazy(() => CreateUsingScope(Namespaces)); + public CSharp.TypeSystem.ResolvedUsingScope UsingScope { get; } - public CSharp.TypeSystem.UsingScope UsingScope => usingScope.Value; - - public DecompileRun(DecompilerSettings settings) + public DecompileRun(DecompilerSettings settings, CSharp.TypeSystem.ResolvedUsingScope usingScope) { this.Settings = settings ?? throw new ArgumentNullException(nameof(settings)); - } - - CSharp.TypeSystem.UsingScope CreateUsingScope(HashSet requiredNamespacesSuperset) - { - var usingScope = new CSharp.TypeSystem.UsingScope(); - foreach (var ns in requiredNamespacesSuperset) - { - string[] parts = ns.Split('.'); - AstType nsType = new SimpleType(parts[0]); - for (int i = 1; i < parts.Length; i++) - { - nsType = new MemberType { Target = nsType, MemberName = parts[i] }; - } - var reference = nsType.ToTypeReference(CSharp.Resolver.NameLookupMode.TypeInUsingDeclaration) - as CSharp.TypeSystem.TypeOrNamespaceReference; - if (reference != null) - usingScope.Usings.Add(reference); - } - return usingScope; + this.UsingScope = usingScope ?? throw new ArgumentNullException(nameof(usingScope)); } } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 3ecc483e8..a0eeab536 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -341,7 +341,6 @@ - diff --git a/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs index 39453f375..330300953 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs @@ -52,7 +52,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms public Metadata.MetadataFile PEFile => TypeSystem.MainModule.MetadataFile; internal DecompileRun? DecompileRun { get; set; } - internal ResolvedUsingScope? UsingScope => DecompileRun?.UsingScope.Resolve(TypeSystem); + internal ResolvedUsingScope? UsingScope => DecompileRun?.UsingScope; CSharpResolver? csharpResolver; diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs index fd72e6259..c983e354b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs +++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs @@ -831,7 +831,8 @@ namespace ICSharpCode.Decompiler.TypeSystem } } - public static INamespace GetNamespaceByFullName(this ICompilation compilation, string name) +#nullable enable + public static INamespace? GetNamespaceByFullName(this ICompilation compilation, string? name) { if (string.IsNullOrEmpty(name)) return compilation.RootNamespace;