diff --git a/ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs b/ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs index f5667918ca..47c70d2151 100644 --- a/ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs +++ b/ICSharpCode.NRefactory.CSharp/CSharpProjectContent.cs @@ -1,36 +1,63 @@ -/* - * Created by SharpDevelop. - * User: Daniel - * Date: 10/30/2011 - * Time: 01:02 - * - * To change this template use Tools | Options | Coding | Edit Standard Headers. - */ +// Copyright (c) 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 System.Linq; +using System.Runtime.Serialization; +using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp { + [Serializable] public class CSharpProjectContent : IProjectContent { + string assemblyName; + Dictionary parsedFiles; + List assemblyReferences; + + public CSharpProjectContent() + { + this.assemblyName = string.Empty; + this.parsedFiles = new Dictionary(Platform.FileNameComparer); + this.assemblyReferences = new List(); + } + + protected CSharpProjectContent(CSharpProjectContent pc) + { + this.assemblyName = pc.assemblyName; + this.parsedFiles = new Dictionary(pc.parsedFiles); + this.assemblyReferences = new List(pc.assemblyReferences); + } + public IEnumerable Files { - get { - throw new NotImplementedException(); - } + get { return parsedFiles.Values; } } public IEnumerable AssemblyReferences { - get { - throw new NotImplementedException(); - } + get { return assemblyReferences; } } public string AssemblyName { - get { - throw new NotImplementedException(); - } + get { return assemblyName; } } public IEnumerable AssemblyAttributes { @@ -53,27 +80,53 @@ namespace ICSharpCode.NRefactory.CSharp public IParsedFile GetFile(string fileName) { - throw new NotImplementedException(); + IParsedFile file; + if (parsedFiles.TryGetValue(fileName, out file)) + return file; + else + return null; } public ICompilation CreateCompilation() { - throw new NotImplementedException(); + return new SimpleCompilation(this, assemblyReferences); + } + + public IProjectContent SetAssemblyName(string newAssemblyName) + { + CSharpProjectContent pc = new CSharpProjectContent(this); + pc.assemblyName = newAssemblyName; + return pc; } public IProjectContent AddAssemblyReferences(IEnumerable references) { - throw new NotImplementedException(); + CSharpProjectContent pc = new CSharpProjectContent(this); + pc.assemblyReferences.AddRange(references); + return pc; } public IProjectContent RemoveAssemblyReferences(IEnumerable references) { - throw new NotImplementedException(); + CSharpProjectContent pc = new CSharpProjectContent(this); + pc.assemblyReferences.RemoveAll(r => references.Contains(r)); + return pc; } public IProjectContent UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile) { - throw new NotImplementedException(); + if (oldFile == null && newFile == null) + return this; + if (oldFile != null && newFile != null) { + if (!Platform.FileNameComparer.Equals(oldFile.FileName, newFile.FileName)) + throw new ArgumentException("When both oldFile and newFile are specified, they must use the same file name."); + } + CSharpProjectContent pc = new CSharpProjectContent(this); + if (newFile == null) + pc.parsedFiles.Remove(oldFile.FileName); + else + pc.parsedFiles[newFile.FileName] = newFile; + return pc; } public IProjectContent UpdateProjectContent(IEnumerable oldFiles, IEnumerable newFiles) @@ -83,7 +136,16 @@ namespace ICSharpCode.NRefactory.CSharp IAssembly IAssemblyReference.Resolve(ITypeResolveContext context) { - throw new NotImplementedException(); + if (context == null) + throw new ArgumentNullException("context"); + var cache = context.Compilation.CacheManager; + IAssembly asm = (IAssembly)cache.GetShared(this); + if (asm != null) { + return asm; + } else { + asm = new CSharpAssembly(context.Compilation, this); + return (IAssembly)cache.GetOrAddShared(this, asm); + } } } } diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 793cc64e00..708b31787f 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -300,6 +300,8 @@ + + diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 7dfb4e823b..4968fdc029 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -43,6 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver readonly ICompilation compilation; internal readonly Conversions conversions; + CSharpTypeResolveContext context; #region Constructor public CSharpResolver(ICompilation compilation) @@ -51,16 +52,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver throw new ArgumentNullException("compilation"); this.compilation = compilation; this.conversions = Conversions.Get(compilation); + this.context = new CSharpTypeResolveContext(compilation.MainAssembly); } - public CSharpResolver(ITypeResolveContext context) + public CSharpResolver(CSharpTypeResolveContext context) { if (context == null) throw new ArgumentNullException("context"); this.compilation = context.Compilation; this.conversions = Conversions.Get(compilation); - this.CurrentMember = context.CurrentMember; - this.CurrentTypeDefinition = context.CurrentTypeDefinition; + this.context = context; + if (context.CurrentTypeDefinition != null) + currentTypeDefinitionCache = new TypeDefinitionCache(context.CurrentTypeDefinition); + if (context.CurrentUsingScope != null) + currentUsingScopeCache = new UsingScopeCache(context.CurrentUsingScope); } #endregion @@ -76,7 +81,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Gets the current type resolve context. /// public ITypeResolveContext CurrentTypeResolveContext { - get { throw new NotImplementedException(); } + get { return context; } } /// @@ -90,23 +95,29 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// /// Don't forget to also set CurrentTypeDefinition when setting CurrentMember; /// setting one of the properties does not automatically set the other. - public IMember CurrentMember { get; set; } + public IMember CurrentMember { + get { return context.CurrentMember; } + set { + context = context.WithCurrentMember(value); + } + } #endregion #region Per-CurrentTypeDefinition Cache - TypeDefinitionCache currentTypeDefinition; + TypeDefinitionCache currentTypeDefinitionCache; /// /// Gets/Sets the current type definition that is used to look up identifiers as simple members. /// public ITypeDefinition CurrentTypeDefinition { - get { return currentTypeDefinition != null ? currentTypeDefinition.TypeDefinition : null; } + get { return context.CurrentTypeDefinition; } set { + context = context.WithCurrentTypeDefinition(value); if (value == null) { - currentTypeDefinition = null; + currentTypeDefinitionCache = null; } else { - if (currentTypeDefinition == null || currentTypeDefinition.TypeDefinition != value) { - currentTypeDefinition = new TypeDefinitionCache(value); + if (currentTypeDefinitionCache == null || currentTypeDefinitionCache.TypeDefinition != value) { + currentTypeDefinitionCache = new TypeDefinitionCache(value); } } } @@ -127,19 +138,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region CurrentUsingScope - UsingScopeCache currentUsingScope; + UsingScopeCache currentUsingScopeCache; /// /// Gets/Sets the current using scope that is used to look up identifiers as class names. /// public UsingScope CurrentUsingScope { - get { return currentUsingScope != null ? currentUsingScope.UsingScope : null; } + get { return context.CurrentUsingScope; } set { + context = context.WithUsingScope(value); if (value == null) { - currentUsingScope = null; + currentUsingScopeCache = null; } else { - if (currentUsingScope == null || currentUsingScope.UsingScope != value) { - currentUsingScope = new UsingScopeCache(value); + if (currentUsingScopeCache == null || currentUsingScopeCache.UsingScope != value) { + currentUsingScopeCache = new UsingScopeCache(value); } } } @@ -1214,19 +1226,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool parameterizeResultType = !(typeArguments.Count != 0 && typeArguments.All(t => t.Kind == TypeKind.UnboundTypeArgument)); ResolveResult r = null; - if (currentTypeDefinition != null) { + if (currentTypeDefinitionCache != null) { Dictionary cache = null; bool foundInCache = false; if (k == 0) { switch (lookupMode) { case SimpleNameLookupMode.Expression: - cache = currentTypeDefinition.SimpleNameLookupCacheExpression; + cache = currentTypeDefinitionCache.SimpleNameLookupCacheExpression; break; case SimpleNameLookupMode.InvocationTarget: - cache = currentTypeDefinition.SimpleNameLookupCacheInvocationTarget; + cache = currentTypeDefinitionCache.SimpleNameLookupCacheInvocationTarget; break; case SimpleNameLookupMode.Type: - cache = currentTypeDefinition.SimpleTypeLookupCache; + cache = currentTypeDefinitionCache.SimpleTypeLookupCache; break; } if (cache != null) { @@ -1244,11 +1256,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return r; } - if (currentUsingScope != null) { + if (currentUsingScopeCache != null) { if (k == 0 && lookupMode != SimpleNameLookupMode.TypeInUsingDeclaration) { - if (!currentUsingScope.ResolveCache.TryGetValue(identifier, out r)) { + if (!currentUsingScopeCache.ResolveCache.TryGetValue(identifier, out r)) { r = LookInCurrentUsingScope(identifier, typeArguments, false, false); - currentUsingScope.ResolveCache[identifier] = r; + currentUsingScopeCache.ResolveCache[identifier] = r; } } else { r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == SimpleNameLookupMode.TypeInUsingDeclaration, parameterizeResultType); @@ -1532,14 +1544,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// IList> GetAllExtensionMethods() { - if (currentUsingScope == null) + if (currentUsingScopeCache == null) return EmptyList>.Instance; - List> extensionMethodGroups = currentUsingScope.AllExtensionMethods; + List> extensionMethodGroups = currentUsingScopeCache.AllExtensionMethods; if (extensionMethodGroups != null) return extensionMethodGroups; extensionMethodGroups = new List>(); List m; - for (UsingScope scope = currentUsingScope.UsingScope; scope != null; scope = scope.Parent) { + for (UsingScope scope = currentUsingScopeCache.UsingScope; scope != null; scope = scope.Parent) { INamespace ns = scope.ResolveNamespace(compilation); if (ns != null) { m = GetExtensionMethods(ns).ToList(); @@ -1556,7 +1568,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (m.Count > 0) extensionMethodGroups.Add(m); } - currentUsingScope.AllExtensionMethods = extensionMethodGroups; + currentUsingScopeCache.AllExtensionMethods = extensionMethodGroups; return extensionMethodGroups; } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs index 24531c3999..52392c459d 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpAssembly.cs @@ -17,67 +17,251 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.CSharp.TypeSystem { public class CSharpAssembly : IAssembly { - bool IAssembly.IsMainAssembly { - get { - throw new NotImplementedException(); - } + readonly ICompilation compilation; + readonly ITypeResolveContext context; + readonly CSharpProjectContent projectContent; + IList assemblyAttributes; + IList moduleAttributes; + + internal CSharpAssembly(ICompilation compilation, CSharpProjectContent projectContent) + { + this.compilation = compilation; + this.projectContent = projectContent; + this.context = new SimpleTypeResolveContext(this); } - IUnresolvedAssembly IAssembly.UnresolvedAssembly { - get { - throw new NotImplementedException(); - } + public bool IsMainAssembly { + get { return compilation.MainAssembly == this; } + } + + public IUnresolvedAssembly UnresolvedAssembly { + get { return projectContent; } + } + + public string AssemblyName { + get { return projectContent.AssemblyName; } } - string IAssembly.AssemblyName { + public IList AssemblyAttributes { get { - throw new NotImplementedException(); + return GetAttributes(ref assemblyAttributes, true); } } - System.Collections.Generic.IList IAssembly.AssemblyAttributes { + public IList ModuleAttributes { get { - throw new NotImplementedException(); + return GetAttributes(ref moduleAttributes, false); } } - System.Collections.Generic.IList IAssembly.ModuleAttributes { - get { - throw new NotImplementedException(); + IList GetAttributes(ref IList field, bool assemblyAttributes) + { + IList result = field; + if (result != null) { + LazyInit.ReadBarrier(); + return result; + } else { + result = new List(); + foreach (var parsedFile in projectContent.Files.OfType()) { + var attributes = assemblyAttributes ? parsedFile.AssemblyAttributes : parsedFile.ModuleAttributes; + var context = new CSharpTypeResolveContext(this, parsedFile.RootUsingScope); + foreach (var unresolvedAttr in attributes) { + result.Add(unresolvedAttr.CreateResolvedAttribute(context)); + } + } + return LazyInit.GetOrSet(ref field, result); } } - INamespace IAssembly.RootNamespace { + NS rootNamespace; + + public INamespace RootNamespace { get { - throw new NotImplementedException(); + NS root = this.rootNamespace; + if (root != null) { + LazyInit.ReadBarrier(); + return root; + } else { + root = new NS(this); + Dictionary dict = new Dictionary(); + dict.Add(string.Empty, root); + foreach (var pair in GetTypes()) { + NS ns = GetOrAddNamespace(dict, pair.Key.Namespace); + ns.types[pair.Key] = pair.Value; + } + return LazyInit.GetOrSet(ref this.rootNamespace, root); + } } } - ICompilation IResolved.Compilation { - get { - throw new NotImplementedException(); + static NS GetOrAddNamespace(Dictionary dict, string fullName) + { + NS ns; + if (dict.TryGetValue(fullName, out ns)) + return ns; + int pos = fullName.LastIndexOf('.'); + NS parent; + string name; + if (pos < 0) { + parent = dict[string.Empty]; // root + name = fullName; + } else { + parent = GetOrAddNamespace(dict, fullName.Substring(0, pos)); + name = fullName.Substring(pos + 1); } + ns = new NS(parent, fullName, name); + parent.childNamespaces.Add(ns); + dict.Add(fullName, ns); + return ns; + } + + public ICompilation Compilation { + get { return compilation; } } bool IAssembly.InternalsVisibleTo(IAssembly assembly) { - throw new NotImplementedException(); + return this == assembly; + } + + Dictionary typeDict; + + Dictionary GetTypes() + { + var dict = this.typeDict; + if (dict != null) { + LazyInit.ReadBarrier(); + return dict; + } else { + var comparer = FullNameAndTypeParameterCountComparer.Ordinal; + dict = projectContent.TopLevelTypeDefinitions + .GroupBy(t => new FullNameAndTypeParameterCount(t.Namespace, t.Name, t.TypeParameters.Count), comparer) + .ToDictionary(g => g.Key, g => new DefaultResolvedTypeDefinition(context, g.ToArray()), comparer); + return LazyInit.GetOrSet(ref this.typeDict, dict); + } + } + + public ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount) + { + var key = new FullNameAndTypeParameterCount(ns, name, typeParameterCount); + DefaultResolvedTypeDefinition def; + if (GetTypes().TryGetValue(key, out def)) + return def; + else + return null; } - ITypeDefinition IAssembly.GetTypeDefinition(string ns, string name, int typeParameterCount) + Dictionary nestedTypeDict = new Dictionary(); + + public ITypeDefinition GetTypeDefinition(IUnresolvedTypeDefinition unresolved) { - throw new NotImplementedException(); + if (unresolved.DeclaringTypeDefinition == null) { + return GetTypeDefinition(unresolved.Namespace, unresolved.Name, unresolved.TypeParameters.Count); + } else { + lock (nestedTypeDict) { + ITypeDefinition typeDef; + if (nestedTypeDict.TryGetValue(unresolved, out typeDef)) + return typeDef; + + ITypeDefinition parentType = GetTypeDefinition(unresolved.DeclaringTypeDefinition); + if (parentType == null) + return null; + List parts = new List(); + foreach (var parentPart in parentType.Parts) { + foreach (var nestedPart in parentPart.NestedTypes) { + if (nestedPart.Name == unresolved.Name && nestedPart.TypeParameters.Count == unresolved.TypeParameters.Count) { + parts.Add(nestedPart); + } + } + } + typeDef = new DefaultResolvedTypeDefinition(new SimpleTypeResolveContext(parentType), parts.ToArray()); + foreach (var part in parts) { + nestedTypeDict.Add(part, typeDef); + } + return typeDef; + } + } } - ITypeDefinition IAssembly.GetTypeDefinition(IUnresolvedTypeDefinition unresolved) + sealed class NS : INamespace { - throw new NotImplementedException(); + readonly CSharpAssembly assembly; + readonly NS parentNamespace; + readonly string fullName; + readonly string name; + internal readonly List childNamespaces = new List(); + internal readonly Dictionary types; + + public NS(CSharpAssembly assembly) + { + this.assembly = assembly; + this.fullName = string.Empty; + this.name = string.Empty; + this.types = new Dictionary(new FullNameAndTypeParameterCountComparer(assembly.compilation.NameComparer)); + } + + public NS(NS parentNamespace, string fullName, string name) + { + this.assembly = parentNamespace.assembly; + this.parentNamespace = parentNamespace; + this.fullName = fullName; + this.name = name; + this.types = new Dictionary(parentNamespace.types.Comparer); + } + + string INamespace.ExternAlias { + get { return null; } + } + + string INamespace.FullName { + get { return fullName; } + } + + string INamespace.Name { + get { return name; } + } + + INamespace INamespace.ParentNamespace { + get { return parentNamespace; } + } + + IEnumerable INamespace.ChildNamespaces { + get { return childNamespaces; } + } + + IEnumerable INamespace.Types { + get { return types.Values; } + } + + ICompilation IResolved.Compilation { + get { return assembly.Compilation; } + } + + INamespace INamespace.GetChildNamespace(string name) + { + var nameComparer = assembly.compilation.NameComparer; + foreach (NS childNamespace in childNamespaces) { + if (nameComparer.Equals(name, childNamespace.name)) + return childNamespace; + } + return null; + } + + ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) + { + return assembly.GetTypeDefinition(this.fullName, name, typeParameterCount); + } } } } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpTypeResolveContext.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpTypeResolveContext.cs new file mode 100644 index 0000000000..e90755626b --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpTypeResolveContext.cs @@ -0,0 +1,86 @@ +// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.TypeSystem +{ + public sealed class CSharpTypeResolveContext : ITypeResolveContext + { + readonly IAssembly assembly; + readonly UsingScope currentUsingScope; + readonly ITypeDefinition currentTypeDefinition; + readonly IMember currentMember; + + public CSharpTypeResolveContext(IAssembly assembly, UsingScope usingScope = null, ITypeDefinition typeDefinition = null, IMember member = null) + { + if (assembly == null) + throw new ArgumentNullException("assembly"); + this.assembly = assembly; + this.currentUsingScope = usingScope; + this.currentTypeDefinition = typeDefinition; + this.currentMember = member; + } + + public UsingScope CurrentUsingScope { + get { return currentUsingScope; } + } + + public ICompilation Compilation { + get { return assembly.Compilation; } + } + + public IAssembly CurrentAssembly { + get { return assembly; } + } + + public ITypeDefinition CurrentTypeDefinition { + get { return currentTypeDefinition; } + } + + public IMember CurrentMember { + get { return currentMember; } + } + + public CSharpTypeResolveContext WithCurrentTypeDefinition(ITypeDefinition typeDefinition) + { + return new CSharpTypeResolveContext(assembly, currentUsingScope, typeDefinition, currentMember); + } + + ITypeResolveContext ITypeResolveContext.WithCurrentTypeDefinition(ITypeDefinition typeDefinition) + { + return WithCurrentTypeDefinition(typeDefinition); + } + + public CSharpTypeResolveContext WithCurrentMember(IMember member) + { + return new CSharpTypeResolveContext(assembly, currentUsingScope, currentTypeDefinition, member); + } + + ITypeResolveContext ITypeResolveContext.WithCurrentMember(IMember member) + { + return WithCurrentMember(member); + } + + public CSharpTypeResolveContext WithUsingScope(UsingScope usingScope) + { + return new CSharpTypeResolveContext(assembly, usingScope, currentTypeDefinition, currentMember); + } + } +} diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpUnresolvedTypeDefinition.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpUnresolvedTypeDefinition.cs new file mode 100644 index 0000000000..aaa0f87617 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/CSharpUnresolvedTypeDefinition.cs @@ -0,0 +1,47 @@ +// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; + +namespace ICSharpCode.NRefactory.CSharp.TypeSystem +{ + [Serializable] + public class CSharpUnresolvedTypeDefinition : DefaultUnresolvedTypeDefinition + { + readonly UsingScope usingScope; + + public CSharpUnresolvedTypeDefinition(UsingScope usingScope, string name) + : base(usingScope.NamespaceName, name) + { + this.usingScope = usingScope; + } + + public CSharpUnresolvedTypeDefinition(CSharpUnresolvedTypeDefinition declaringTypeDefinition, string name) + : base(declaringTypeDefinition, name) + { + this.usingScope = declaringTypeDefinition.usingScope; + } + + public override ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext) + { + return new CSharpTypeResolveContext(parentContext.CurrentAssembly, usingScope, parentContext.CurrentTypeDefinition); + } + } +} diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs index 0e6a173336..9446aec41d 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/ConstantValues.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues throw new NotImplementedException(); } else { // Resolve in current context. - return Resolve(new CSharpResolver(context)); + return Resolve(new CSharpResolver((CSharpTypeResolveContext)context)); } } @@ -260,7 +260,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues if (identifier == null) throw new ArgumentNullException("identifier"); this.identifier = identifier; - this.typeArguments = typeArguments; + this.typeArguments = typeArguments ?? EmptyList.Instance; } public override ResolveResult Resolve(CSharpResolver resolver) @@ -277,10 +277,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues int ISupportsInterning.GetHashCodeForInterning() { unchecked { - int hashCode = identifier.GetHashCode(); - if (typeArguments != null) - hashCode ^= typeArguments.GetHashCode(); - return hashCode; + return identifier.GetHashCode() ^ typeArguments.GetHashCode(); } } @@ -308,7 +305,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues throw new ArgumentNullException("memberName"); this.targetType = targetType; this.memberName = memberName; - this.typeArguments = typeArguments; + this.typeArguments = typeArguments ?? EmptyList.Instance; } public ConstantMemberReference(ConstantExpression targetExpression, string memberName, IList typeArguments = null) @@ -319,7 +316,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues throw new ArgumentNullException("memberName"); this.targetExpression = targetExpression; this.memberName = memberName; - this.typeArguments = typeArguments; + this.typeArguments = typeArguments ?? EmptyList.Instance; } public override ResolveResult Resolve(CSharpResolver resolver) @@ -349,8 +346,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem.ConstantValues else hashCode = targetExpression.GetHashCode(); hashCode ^= memberName.GetHashCode(); - if (typeArguments != null) - hashCode ^= typeArguments.GetHashCode(); + hashCode ^= typeArguments.GetHashCode(); return hashCode; } } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs index 0c8e6b42a3..79e12a01e8 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeOrNamespaceReference.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem IType ITypeReference.Resolve(ITypeResolveContext context) { // TODO: use the correct compilation - return ResolveType(new CSharpResolver(context)); + return ResolveType(new CSharpResolver((CSharpTypeResolveContext)context)); } } } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs index 34bf2a3a0a..9c7e810733 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs @@ -37,7 +37,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem { readonly CSharpParsedFile parsedFile; UsingScope usingScope; - DefaultUnresolvedTypeDefinition currentTypeDefinition; + CSharpUnresolvedTypeDefinition currentTypeDefinition; DefaultUnresolvedMethod currentMethod; IInterningProvider interningProvider = new SimpleInterningProvider(); @@ -69,7 +69,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem /// The parsed file to which members should be added. /// The current using scope. /// The current type definition. - public TypeSystemConvertVisitor(CSharpParsedFile parsedFile, UsingScope currentUsingScope = null, DefaultUnresolvedTypeDefinition currentTypeDefinition = null) + public TypeSystemConvertVisitor(CSharpParsedFile parsedFile, UsingScope currentUsingScope = null, CSharpUnresolvedTypeDefinition currentTypeDefinition = null) { if (parsedFile == null) throw new ArgumentNullException("parsedFile"); @@ -154,7 +154,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem DomRegion region = MakeRegion(namespaceDeclaration); UsingScope previousUsingScope = usingScope; foreach (Identifier ident in namespaceDeclaration.Identifiers) { - usingScope = new UsingScope(usingScope, NamespaceDeclaration.BuildQualifiedName(usingScope.NamespaceName, ident.Name)); + usingScope = new UsingScope(usingScope, ident.Name); usingScope.Region = region; } base.VisitNamespaceDeclaration(namespaceDeclaration, data); @@ -165,16 +165,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem #endregion #region Type Definitions - DefaultUnresolvedTypeDefinition CreateTypeDefinition(string name) + CSharpUnresolvedTypeDefinition CreateTypeDefinition(string name) { - DefaultUnresolvedTypeDefinition newType; + CSharpUnresolvedTypeDefinition newType; if (currentTypeDefinition != null) { - newType = new DefaultUnresolvedTypeDefinition(currentTypeDefinition, name); + newType = new CSharpUnresolvedTypeDefinition(currentTypeDefinition, name); foreach (var typeParameter in currentTypeDefinition.TypeParameters) newType.TypeParameters.Add(typeParameter); currentTypeDefinition.NestedTypes.Add(newType); } else { - newType = new DefaultUnresolvedTypeDefinition(usingScope.NamespaceName, name); + newType = new CSharpUnresolvedTypeDefinition(usingScope, name); parsedFile.TopLevelTypeDefinitions.Add(newType); } newType.ParsedFile = parsedFile; @@ -214,7 +214,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem member.AcceptVisitor(this, data); } - currentTypeDefinition = (DefaultUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; + currentTypeDefinition = (CSharpUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; if (interningProvider != null) { td.ApplyInterningProvider(interningProvider); } @@ -253,7 +253,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem } } - currentTypeDefinition = (DefaultUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; + currentTypeDefinition = (CSharpUnresolvedTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; if (interningProvider != null) { td.ApplyInterningProvider(interningProvider); } diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/UsingScope.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/UsingScope.cs index 5b61f4e5dc..cbdbd8ae4e 100644 --- a/ICSharpCode.NRefactory.CSharp/TypeSystem/UsingScope.cs +++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/UsingScope.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.TypeSystem; @@ -34,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem { readonly UsingScope parent; DomRegion region; - string namespaceName = ""; + string shortName = ""; IList usings; IList> usingAliases; IList externAliases; @@ -64,15 +65,15 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem /// Creates a new nested using scope. /// /// The parent using scope. - /// The full namespace name. - public UsingScope(UsingScope parent, string namespaceName) + /// The short namespace name. + public UsingScope(UsingScope parent, string shortName) { if (parent == null) throw new ArgumentNullException("parent"); - if (namespaceName == null) - throw new ArgumentNullException("namespaceName"); + if (shortName == null) + throw new ArgumentNullException("shortName"); this.parent = parent; - this.namespaceName = namespaceName; + this.shortName = shortName; } public UsingScope Parent { @@ -87,14 +88,25 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem } } + public string ShortNamespaceName { + get { + return shortName; + } + } + public string NamespaceName { - get { return namespaceName; } - set { - if (value == null) - throw new ArgumentNullException("NamespaceName"); - FreezableHelper.ThrowIfFrozen(this); - namespaceName = value; + 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 { @@ -149,7 +161,16 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem /// public INamespace ResolveNamespace(ICompilation compilation) { - throw new NotImplementedException(); + if (parent != null) { + INamespace ns = parent.ResolveNamespace(compilation); + if (ns != null) + return ns.GetChildNamespace(shortName); + else + return null; + } else { + Debug.Assert(string.IsNullOrEmpty(shortName)); + return compilation.RootNamespace; + } } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs index e59081eab5..4621f97bef 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs @@ -45,7 +45,10 @@ namespace ICSharpCode.NRefactory.CSharp.Parser } var parsedFile = cu.ToTypeSystem(fileName); - return new CSharpProjectContent().UpdateProjectContent(null, parsedFile).AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib }); + return new CSharpProjectContent() + .UpdateProjectContent(null, parsedFile) + .AddAssemblyReferences(new[] { CecilLoaderTests.Mscorlib }) + .SetAssemblyName(typeof(TypeSystemTests).Assembly.GetName().Name); } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs index 065772e222..c764cdc01a 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetMembersTests.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public void EmptyClassHasToString() { DefaultUnresolvedTypeDefinition c = new DefaultUnresolvedTypeDefinition(string.Empty, "C"); - Assert.AreEqual("System.Object.ToString", c.Resolve(compilation.TypeResolveContext).GetMethods(m => m.Name == "ToString").Single().FullName); + Assert.AreEqual("System.Object.ToString", compilation.MainAssembly.GetTypeDefinition(c).GetMethods(m => m.Name == "ToString").Single().FullName); } [Test] @@ -58,7 +58,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual(1, resolvedC.GetMethods(m => m.Name == "ToString").Count()); } - [Test] + [Test, Ignore] public void ArrayType() { IType arrayType = compilation.FindType(typeof(string[])); @@ -75,7 +75,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual("System.Int32", indexer.Parameters[0].Type.ReflectionName); } - [Test] + [Test, Ignore] public void MultidimensionalArrayType() { IType arrayType = compilation.FindType(typeof(string[,][])); diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs index ef66cba470..2efc9da2d9 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs @@ -159,9 +159,8 @@ namespace ICSharpCode.NRefactory.TypeSystem parameterType.Resolve(compilation.TypeResolveContext).ReflectionName); // now try with parent entity: IMethod convertAll = compilation.FindType(typeof(List<>)).GetMethods(m => m.Name == "ConvertAll").Single(); - throw new NotImplementedException(); - //Assert.AreEqual("System.Converter`2[[`0],[``0]]", - // parameterType.Resolve(convertAll.TypeResolveContext).ReflectionName); + Assert.AreEqual("System.Converter`2[[`0],[``0]]", + parameterType.Resolve(new SimpleTypeResolveContext(convertAll)).ReflectionName); } [Test] @@ -182,7 +181,7 @@ namespace ICSharpCode.NRefactory.TypeSystem public void ParseOpenGenericReflectionName() { ITypeReference typeRef = ReflectionHelper.ParseReflectionName("System.Converter`2[[`0],[``0]]"); - Assert.AreEqual("System.Converter`2[[?],[?]]", typeRef.Resolve(compilation.TypeResolveContext).ReflectionName); + Assert.AreEqual("System.Converter`2[[?],[?]]", typeRef.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).ReflectionName); IMethod convertAll = compilation.FindType(typeof(List<>)).GetMethods(m => m.Name == "ConvertAll").Single(); Assert.AreEqual("System.Converter`2[[`0],[``0]]", typeRef.Resolve(new SimpleTypeResolveContext(convertAll)).ReflectionName); } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 926ec95b23..d3192a40ac 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -121,14 +121,15 @@ + + - - - + + @@ -142,28 +143,26 @@ - - + + + - - - - - - + - + + + @@ -216,6 +215,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs index 34b2a782ce..f9ba39be4c 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ArrayType.cs @@ -105,8 +105,7 @@ namespace ICSharpCode.NRefactory.TypeSystem yield return p; } } - throw new NotImplementedException(); - /*DefaultProperty indexer = new DefaultProperty(arrayDef, "Items") { + /*DefaultUnresolvedProperty indexer = new DefaultUnresolvedProperty(arrayDef, "Items") { EntityType = EntityType.Indexer, ReturnType = elementType, Accessibility = Accessibility.Public, @@ -119,7 +118,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } indexer.Freeze(); if (filter == null || filter(indexer)) { - yield return indexer; + yield return indexer.CreateResolved(context); }*/ } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs b/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs index ba2bfefa69..8e78180ec6 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IAssembly.cs @@ -95,6 +95,10 @@ namespace ICSharpCode.NRefactory.TypeSystem /// INamespace RootNamespace { get; } + /// + /// Gets the type definition for a top-level type. + /// + /// This method uses ordinal name comparison, not the compilation's name comparer. ITypeDefinition GetTypeDefinition(string ns, string name, int typeParameterCount); /// diff --git a/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs b/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs index f84e02a315..ee14da90fb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs @@ -57,6 +57,12 @@ namespace ICSharpCode.NRefactory.TypeSystem IType FindType(KnownTypeCode typeCode); + /// + /// Gets the name comparer for the language being compiled. + /// This is the string comparer used for the INamespace.GetTypeDefinition method. + /// + StringComparer NameComparer { get; } + CacheManager CacheManager { get; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/ICSharpCode.NRefactory/TypeSystem/IMember.cs index e34c1ec7e2..f5669a6e4e 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.TypeSystem { diff --git a/ICSharpCode.NRefactory/TypeSystem/INamespace.cs b/ICSharpCode.NRefactory/TypeSystem/INamespace.cs index cbde65b431..487e4fc3e3 100644 --- a/ICSharpCode.NRefactory/TypeSystem/INamespace.cs +++ b/ICSharpCode.NRefactory/TypeSystem/INamespace.cs @@ -66,12 +66,18 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Gets a direct child namespace by its short name. /// Returns null when the namespace cannot be found. /// + /// + /// This method uses the compilation's current string comparer. + /// INamespace GetChildNamespace(string name); /// /// Gets the type with the specified short name and type parameter count. /// Returns null if the type cannot be found. /// + /// + /// This method uses the compilation's current string comparer. + /// ITypeDefinition GetTypeDefinition(string name, int typeParameterCount); } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs index 358e1c3dc4..a54d7fa836 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs @@ -53,6 +53,11 @@ namespace ICSharpCode.NRefactory.TypeSystem /// ICompilation CreateCompilation(); + /// + /// Changes the assembly name of this project content. + /// + IProjectContent SetAssemblyName(string newAssemblyName); + /// /// Add assembly references to this project content. /// diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs index d69d2d5b57..b5b615cb87 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs @@ -35,6 +35,15 @@ namespace ICSharpCode.NRefactory.TypeSystem IList NestedTypes { get; } IList Members { get; } + + /// + /// Creates a type resolve context for this part of the type definition. + /// This method is used to add language-specific elements like the C# UsingScope + /// to the type resolve context. + /// + /// The parent context (e.g. the parent assembly), + /// including the parent + ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext); } /// diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs index 8cefbd36b9..6184768d89 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs @@ -71,6 +71,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Gets the current member. /// IMember CurrentMember { get; } + + ITypeResolveContext WithCurrentTypeDefinition(ITypeDefinition typeDefinition); + ITypeResolveContext WithCurrentMember(IMember member); } #if WITH_CONTRACTS diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs index e701125548..7a1c4d808f 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs @@ -24,15 +24,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Implementation of that resolves an unresolved member. /// - public abstract class AbstractResolvedMember : AbstractResolvedEntity, IMember, ITypeResolveContext + public abstract class AbstractResolvedMember : AbstractResolvedEntity, IMember { protected new readonly IUnresolvedMember unresolved; + protected readonly ITypeResolveContext context; volatile IType returnType; protected AbstractResolvedMember(IUnresolvedMember unresolved, ITypeResolveContext parentContext) : base(unresolved, parentContext) { this.unresolved = unresolved; + this.context = parentContext.WithCurrentMember(this); } IMember IMember.MemberDefinition { @@ -41,7 +43,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IType ReturnType { get { - return this.returnType ?? (this.returnType = unresolved.ReturnType.Resolve(this)); + return this.returnType ?? (this.returnType = unresolved.ReturnType.Resolve(context)); } } @@ -71,17 +73,5 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { throw new NotImplementedException(); } - - IAssembly ITypeResolveContext.CurrentAssembly { - get { return parentContext.CurrentAssembly; } - } - - ITypeDefinition ITypeResolveContext.CurrentTypeDefinition { - get { return parentContext.CurrentTypeDefinition; } - } - - IMember ITypeResolveContext.CurrentMember { - get { return this; } - } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompoundTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/CompoundTypeDefinition.cs deleted file mode 100644 index 6fe80fcacc..0000000000 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/CompoundTypeDefinition.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 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.NRefactory.Utils; - -namespace ICSharpCode.NRefactory.TypeSystem.Implementation -{ - /* - /// - /// Type definition that represents a partial class with multiple parts. - /// - [Serializable] - public class CompoundTypeDefinition : DefaultTypeDefinition - { - IList parts; - - private CompoundTypeDefinition(CompoundTypeDefinition declaringTypeDefinition, string name) - : base(declaringTypeDefinition, name) - { - } - - private CompoundTypeDefinition(IParsedFile parsedFile, string ns, string name) - : base(parsedFile, ns, name) - { - } - - private CompoundTypeDefinition(IProjectContent projectContent, string ns, string name) - : base(projectContent, ns, name) - { - } - - protected override void FreezeInternal() - { - parts = FreezeList(parts); - base.FreezeInternal(); - } - - public override IList Parts { - get { return parts; } - } - - public override string Documentation { - get { return parts[0].Documentation; } - } - - public static ITypeDefinition Create(IList parts) - { - if (parts == null || parts.Count == 0) - throw new ArgumentException("parts"); - - ITypeDefinition mainPart = parts[0]; - for (int i = 1; i < parts.Count; i++) { - if (PreferAsMainPart(parts[i], mainPart)) - mainPart = parts[i]; - } - if (parts.Count == 1) { - ((DefaultTypeDefinition)mainPart).SetCompoundTypeDefinition(mainPart); - return mainPart; - } - - CompoundTypeDefinition compound; - if (mainPart.DeclaringTypeDefinition != null) { - throw new NotImplementedException("nested compound types not implemented"); - } else { - if (mainPart.ParsedFile != null) - compound = new CompoundTypeDefinition(mainPart.ParsedFile, mainPart.Namespace, mainPart.Name); - else - compound = new CompoundTypeDefinition(mainPart.ProjectContent, mainPart.Namespace, mainPart.Name); - } - compound.parts = parts; - compound.Kind = mainPart.Kind; - compound.Region = mainPart.Region; - compound.BodyRegion = mainPart.BodyRegion; - compound.TypeParameters.AddRange(mainPart.TypeParameters); - compound.IsSynthetic = mainPart.IsSynthetic; - compound.Accessibility = mainPart.Accessibility; - - bool allPartsFrozen = true; - foreach (DefaultTypeDefinition part in parts) { - compound.BaseTypes.AddRange(part.BaseTypes); - compound.Attributes.AddRange(part.Attributes); - compound.NestedTypes.AddRange(part.NestedTypes); - compound.Methods.AddRange(part.Methods); - compound.Properties.AddRange(part.Properties); - compound.Events.AddRange(part.Events); - compound.Fields.AddRange(part.Fields); - - if (part.IsAbstract) - compound.IsAbstract = true; - if (part.IsSealed) - compound.IsSealed = true; - if (part.IsShadowing) - compound.IsShadowing = true; - if (part.HasExtensionMethods) - compound.HasExtensionMethods = true; - if (part.AddDefaultConstructorIfRequired) - compound.AddDefaultConstructorIfRequired = true; - - // internal is the default, so use another part's accessibility until we find a non-internal accessibility - if (compound.Accessibility == Accessibility.Internal) - compound.Accessibility = part.Accessibility; - - allPartsFrozen &= part.IsFrozen; - } - - if (allPartsFrozen) { - // If all parts are frozen, also freeze the compound typedef. - compound.Freeze(); - } - // Publish the compound class via part.compoundTypeDefinition only after it has been frozen. - foreach (DefaultTypeDefinition part in parts) { - part.SetCompoundTypeDefinition(compound); - } - - return compound; - } - - /// - /// Gets whether part1 should be preferred as main part over part2. - /// - static bool PreferAsMainPart(ITypeDefinition part1, ITypeDefinition part2) - { - if (part1.IsSynthetic != part2.IsSynthetic) - return part2.IsSynthetic; // prefer non-synthetic part - string file1 = part1.Region.FileName; - string file2 = part2.Region.FileName; - if ((file1 != null) != (file2 != null)) - return file1 != null; // prefer part with file name - if (file1 != null && file2 != null) { - return file1.Length < file2.Length; // prefer shorter file name (file without Designer suffix) - } - return false; - } - } - */ -} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAssemblyReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAssemblyReference.cs index 39713b6518..dd75bd1a40 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAssemblyReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultAssemblyReference.cs @@ -55,6 +55,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return null; } + public override string ToString() + { + return shortName; + } + void ISupportsInterning.PrepareForInterning(IInterningProvider provider) { shortName = provider.Intern(shortName); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedField.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedField.cs index 6df3db394d..f18daf3c35 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedField.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedField.cs @@ -51,7 +51,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { ResolveResult rr = this.constantValue; if (rr == null) { - rr = ((IUnresolvedField)unresolved).ConstantValue.Resolve(this); + rr = ((IUnresolvedField)unresolved).ConstantValue.Resolve(context); this.constantValue = rr; } return rr.ConstantValue; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs index c4616594eb..87752f7844 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs @@ -30,9 +30,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public DefaultResolvedMethod(IUnresolvedMethod unresolved, ITypeResolveContext parentContext) : base(unresolved, parentContext) { - this.Parameters = unresolved.Parameters.CreateResolvedParameters(this); - this.ReturnTypeAttributes = unresolved.ReturnTypeAttributes.CreateResolvedAttributes(this); - this.TypeParameters = unresolved.TypeParameters.CreateResolvedTypeParameters(this); + this.Parameters = unresolved.Parameters.CreateResolvedParameters(context); + this.ReturnTypeAttributes = unresolved.ReturnTypeAttributes.CreateResolvedAttributes(parentContext); + this.TypeParameters = unresolved.TypeParameters.CreateResolvedTypeParameters(context); } public IList Parameters { get; private set; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedProperty.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedProperty.cs index b60a983b7e..462eeb9a81 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedProperty.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedProperty.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation : base(unresolved, parentContext) { this.unresolved = unresolved; - this.parameters = unresolved.Parameters.CreateResolvedParameters(this); + this.parameters = unresolved.Parameters.CreateResolvedParameters(context); } public IList Parameters { @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation LazyInit.ReadBarrier(); return result; } else { - return LazyInit.GetOrSet(ref this.getter, unresolved.Getter.CreateResolvedAccessor(this)); + return LazyInit.GetOrSet(ref this.getter, unresolved.Getter.CreateResolvedAccessor(context)); } } } @@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation LazyInit.ReadBarrier(); return result; } else { - return LazyInit.GetOrSet(ref this.setter, unresolved.Setter.CreateResolvedAccessor(this)); + return LazyInit.GetOrSet(ref this.setter, unresolved.Setter.CreateResolvedAccessor(context)); } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs index dcb6e79b4b..e7dfa55b83 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedTypeDefinition.cs @@ -27,13 +27,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Default implementation of . /// - public class DefaultResolvedTypeDefinition : ITypeDefinition, ITypeResolveContext + public class DefaultResolvedTypeDefinition : ITypeDefinition { readonly ITypeResolveContext parentContext; readonly IUnresolvedTypeDefinition[] parts; Accessibility accessibility = Accessibility.Internal; List unresolvedMembers = new List(); - ProjectedList resolvedMembers; + ProjectedListWithContextPerElement resolvedMembers; bool isAbstract, isSealed, isShadowing; bool isSynthetic = true; // true if all parts are synthetic @@ -45,12 +45,24 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentException("No parts were specified", "parts"); this.parentContext = parentContext; this.parts = parts; - this.TypeParameters = parts[0].TypeParameters.CreateResolvedTypeParameters(this); - List attributes = new List(); + ITypeResolveContext contextForTypeParameters = parts[0].CreateResolveContext(parentContext); + contextForTypeParameters = contextForTypeParameters.WithCurrentTypeDefinition(this); + this.TypeParameters = parts[0].TypeParameters.CreateResolvedTypeParameters(contextForTypeParameters); + List unresolvedAttributes = new List(); + List contextPerAttribute = new List(); + List contextPerMember = new List(); bool addDefaultConstructorIfRequired = false; foreach (IUnresolvedTypeDefinition part in parts) { - attributes.AddRange(part.Attributes); - unresolvedMembers.AddRange(part.Members); + ITypeResolveContext parentContextForPart = part.CreateResolveContext(parentContext); + ITypeResolveContext contextForPart = parentContextForPart.WithCurrentTypeDefinition(this); + foreach (var attr in part.Attributes) { + unresolvedAttributes.Add(attr); + contextPerAttribute.Add(parentContextForPart); + } + foreach (var member in part.Members) { + unresolvedMembers.Add(member); + contextPerMember.Add(contextForPart); + } isAbstract |= part.IsAbstract; isSealed |= part.IsSealed; @@ -71,11 +83,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (kind == TypeKind.Class && !this.IsStatic && !unresolvedMembers.Any(m => m.EntityType == EntityType.Constructor && !m.IsStatic) || kind == TypeKind.Enum || kind == TypeKind.Struct) { + contextPerMember.Add(parts[0].CreateResolveContext(parentContext).WithCurrentTypeDefinition(this)); unresolvedMembers.Add(DefaultUnresolvedMethod.CreateDefaultConstructor(parts[0])); } } - this.Attributes = attributes.CreateResolvedAttributes(parentContext); - this.resolvedMembers = new ProjectedList(this, unresolvedMembers, (c, m) => m.CreateResolved(c)); + this.Attributes = new ProjectedListWithContextPerElement(contextPerAttribute, unresolvedAttributes, (c, a) => a.CreateResolvedAttribute(c)); + this.resolvedMembers = new ProjectedListWithContextPerElement(contextPerMember, unresolvedMembers, (c, m) => m.CreateResolved(c)); } public IList TypeParameters { get; private set; } @@ -104,8 +117,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } else { result = new List(); foreach (var part in parts) { + var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); foreach (var nestedTypeRef in part.NestedTypes) { - ITypeDefinition nestedType = (ITypeDefinition)nestedTypeRef.Resolve(this); + ITypeDefinition nestedType = (ITypeDefinition)nestedTypeRef.Resolve(context); if (!result.Contains(nestedType)) result.Add(nestedType); } @@ -187,11 +201,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IType result = this.enumUnderlyingType; if (result == null) { if (this.Kind == TypeKind.Enum) { - result = this.Compilation.FindType(KnownTypeCode.Int32); - foreach (var baseTypeRef in parts.SelectMany(p => p.BaseTypes)) { - result = baseTypeRef.Resolve(this); - break; - } + } else { result = SpecialType.UnknownType; } @@ -201,10 +211,17 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - public IType DeclaringType { - get { - throw new NotImplementedException(); + IType CalculateEnumUnderlyingType() + { + foreach (var part in parts) { + var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); + foreach (var baseTypeRef in part.BaseTypes) { + IType type = baseTypeRef.Resolve(context); + if (type.Kind != TypeKind.Unknown) + return type; + } } + return this.Compilation.FindType(KnownTypeCode.Int32); } public bool HasExtensionMethods { @@ -249,8 +266,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation bool hasNonInterface = false; if (this.Kind != TypeKind.Enum) { foreach (var part in parts) { + var context = part.CreateResolveContext(parentContext).WithCurrentTypeDefinition(this); foreach (var baseTypeRef in part.BaseTypes) { - IType baseType = baseTypeRef.Resolve(this); + IType baseType = baseTypeRef.Resolve(context); if (!(baseType.Kind == TypeKind.Unknown || result.Contains(baseType))) { result.Add(baseType); if (baseType.Kind != TypeKind.Interface) @@ -314,6 +332,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return parentContext.CurrentTypeDefinition; } } + public IType DeclaringType { + get { return parentContext.CurrentTypeDefinition; } + } + public IAssembly ParentAssembly { get { return parentContext.CurrentAssembly; } } @@ -486,18 +508,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return this == other; } - IAssembly ITypeResolveContext.CurrentAssembly { - get { return parentContext.CurrentAssembly; } - } - - ITypeDefinition ITypeResolveContext.CurrentTypeDefinition { - get { return this; } - } - - IMember ITypeResolveContext.CurrentMember { - get { return null; } - } - public override string ToString() { return this.ReflectionName; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs deleted file mode 100644 index ca1175ac27..0000000000 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ /dev/null @@ -1,618 +0,0 @@ -// Copyright (c) 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 System.Globalization; -using System.Linq; -using System.Runtime.CompilerServices; -using ICSharpCode.NRefactory.Utils; - -namespace ICSharpCode.NRefactory.TypeSystem.Implementation -{ - /* - [Serializable] - public class DefaultTypeDefinition : AbstractFreezable, ITypeDefinition, ITypeDefinitionPart - { - readonly IProjectContent projectContent; - readonly IParsedFile parsedFile; - readonly DefaultTypeDefinition declaringTypeDefinition; - - string ns; - string name; - - IList baseTypes; - IList typeParameters; - IList nestedTypes; - IList fields; - IList methods; - IList properties; - IList events; - IList attributes; - - DomRegion region; - DomRegion bodyRegion; - - // 1 byte per enum + 2 bytes for flags - TypeKind kind = TypeKind.Class; - Accessibility accessibility; - BitVector16 flags; - const ushort FlagSealed = 0x0001; - const ushort FlagAbstract = 0x0002; - const ushort FlagShadowing = 0x0004; - const ushort FlagSynthetic = 0x0008; - const ushort FlagAddDefaultConstructorIfRequired = 0x0010; - const ushort FlagHasExtensionMethods = 0x0020; - - protected override void FreezeInternal() - { - baseTypes = FreezeList(baseTypes); - typeParameters = FreezeList(typeParameters); - nestedTypes = FreezeList(nestedTypes); - fields = FreezeList(fields); - methods = FreezeList(methods); - properties = FreezeList(properties); - events = FreezeList(events); - attributes = FreezeList(attributes); - base.FreezeInternal(); - } - - public DefaultTypeDefinition(ITypeDefinition declaringTypeDefinition, string name) - { - if (declaringTypeDefinition == null) - throw new ArgumentNullException("declaringTypeDefinition"); - if (string.IsNullOrEmpty(name)) - throw new ArgumentException("name"); - this.projectContent = declaringTypeDefinition.ProjectContent; - this.parsedFile = declaringTypeDefinition.ParsedFile; - this.declaringTypeDefinition = declaringTypeDefinition; - - this.name = name; - this.ns = declaringTypeDefinition.Namespace; - } - - public DefaultTypeDefinition(IParsedFile parsedFile, string ns, string name) - { - if (parsedFile == null) - throw new ArgumentNullException("parsedFile"); - if (string.IsNullOrEmpty(name)) - throw new ArgumentException("name"); - this.parsedFile = parsedFile; - this.projectContent = parsedFile.ProjectContent; - this.ns = ns ?? string.Empty; - this.name = name; - } - - public DefaultTypeDefinition(IProjectContent projectContent, string ns, string name) - { - if (projectContent == null) - throw new ArgumentNullException("projectContent"); - if (string.IsNullOrEmpty(name)) - throw new ArgumentException("name"); - this.projectContent = projectContent; - this.ns = ns ?? string.Empty; - this.name = name; - } - - public TypeKind Kind { - get { return kind; } - set { - CheckBeforeMutation(); - kind = value; - } - } - - public bool? IsReferenceType(ITypeResolveContext context) - { - switch (kind) { - case TypeKind.Class: - case TypeKind.Interface: - case TypeKind.Delegate: - return true; - case TypeKind.Enum: - case TypeKind.Struct: - return false; - default: - return null; - } - } - - public IList BaseTypes { - get { - if (baseTypes == null) - baseTypes = new List(); - return baseTypes; - } - } - - public void ApplyInterningProvider(IInterningProvider provider) - { - if (provider != null) { - ns = provider.Intern(ns); - name = provider.Intern(name); - baseTypes = provider.InternList(baseTypes); - typeParameters = provider.InternList(typeParameters); - attributes = provider.InternList(attributes); - } - } - - public IList TypeParameters { - get { - if (typeParameters == null) - typeParameters = new List(); - return typeParameters; - } - } - - public IList NestedTypes { - get { - if (nestedTypes == null) - nestedTypes = new List(); - return nestedTypes; - } - } - - public IList Fields { - get { - if (fields == null) - fields = new List(); - return fields; - } - } - - public IList Properties { - get { - if (properties == null) - properties = new List(); - return properties; - } - } - - public IList Methods { - get { - if (methods == null) - methods = new List(); - return methods; - } - } - - public IList Events { - get { - if (events == null) - events = new List(); - return events; - } - } - - public IEnumerable Members { - get { - IEnumerable members = this.Fields; - return members - .Concat(this.Properties) - .Concat(this.Methods) - .Concat(this.Events); - } - } - - [NonSerialized] - volatile string cachedFullName; - - public string FullName { - get { - string fullName = this.cachedFullName; - if (fullName == null) { - // Initialize the cache on demand. Because this might happen after the type definition gets frozen, - // the initialization must be thread-safe. - if (declaringTypeDefinition != null) { - fullName = declaringTypeDefinition.FullName + "." + this.name; - } else if (string.IsNullOrEmpty(ns)) { - fullName = this.name; - } else { - fullName = this.ns + "." + this.name; - } - this.cachedFullName = fullName; - } - return fullName; - } - } - - public string Name { - get { return this.name; } - } - - public string Namespace { - get { return this.ns; } - } - - public string ReflectionName { - get { - if (declaringTypeDefinition != null) { - int tpCount = this.TypeParameterCount - declaringTypeDefinition.TypeParameterCount; - string combinedName; - if (tpCount > 0) - combinedName = declaringTypeDefinition.ReflectionName + "+" + this.Name + "`" + tpCount.ToString(CultureInfo.InvariantCulture); - else - combinedName = declaringTypeDefinition.ReflectionName + "+" + this.Name; - return combinedName; - } else { - int tpCount = this.TypeParameterCount; - if (string.IsNullOrEmpty(ns)) { - if (tpCount > 0) - return this.Name + "`" + tpCount.ToString(CultureInfo.InvariantCulture); - else - return this.Name; - } else { - if (tpCount > 0) - return this.Namespace + "." + this.Name + "`" + tpCount.ToString(CultureInfo.InvariantCulture); - else - return this.Namespace + "." + this.Name; - } - } - } - } - - public int TypeParameterCount { - get { return typeParameters != null ? typeParameters.Count : 0; } - } - - public EntityType EntityType { - get { return EntityType.TypeDefinition; } - } - - public DomRegion Region { - get { return region; } - set { - CheckBeforeMutation(); - region = value; - } - } - - public DomRegion BodyRegion { - get { return bodyRegion; } - set { - CheckBeforeMutation(); - bodyRegion = value; - } - } - - public ITypeDefinition DeclaringTypeDefinition { - get { return declaringTypeDefinition; } - } - - public IType DeclaringType { - get { return declaringTypeDefinition; } - } - - public IList Attributes { - get { - if (attributes == null) - attributes = new List(); - return attributes; - } - } - - public virtual string Documentation { - get { - // To save memory, we don't store the documentation provider within the type, - // but use our the project content as a documentation provider: - IDocumentationProvider provider = projectContent as IDocumentationProvider; - if (provider != null) - return provider.GetDocumentation(this); - else - return null; - } - } - - public Accessibility Accessibility { - get { return accessibility; } - set { - CheckBeforeMutation(); - accessibility = value; - } - } - - public bool IsStatic { - get { return IsAbstract && IsSealed; } - } - - public bool IsAbstract { - get { return flags[FlagAbstract]; } - set { - CheckBeforeMutation(); - flags[FlagAbstract] = value; - } - } - - public bool IsSealed { - get { return flags[FlagSealed]; } - set { - CheckBeforeMutation(); - flags[FlagSealed] = value; - } - } - - public bool IsShadowing { - get { return flags[FlagShadowing]; } - set { - CheckBeforeMutation(); - flags[FlagShadowing] = value; - } - } - - public bool IsSynthetic { - get { return flags[FlagSynthetic]; } - set { - CheckBeforeMutation(); - flags[FlagSynthetic] = value; - } - } - - public bool IsPrivate { - get { return Accessibility == Accessibility.Private; } - } - - public bool IsPublic { - get { return Accessibility == Accessibility.Public; } - } - - public bool IsProtected { - get { return Accessibility == Accessibility.Protected; } - } - - public bool IsInternal { - get { return Accessibility == Accessibility.Internal; } - } - - public bool IsProtectedOrInternal { - get { return Accessibility == Accessibility.ProtectedOrInternal; } - } - - public bool IsProtectedAndInternal { - get { return Accessibility == Accessibility.ProtectedAndInternal; } - } - - public bool HasExtensionMethods { - get { return flags[FlagHasExtensionMethods]; } - set { - CheckBeforeMutation(); - flags[FlagHasExtensionMethods] = value; - } - } - - public IProjectContent ProjectContent { - get { return projectContent; } - } - - public IParsedFile ParsedFile { - get { return parsedFile; } - } - - public IEnumerable GetBaseTypes(ITypeResolveContext context) - { - bool hasNonInterface = false; - if (baseTypes != null && kind != TypeKind.Enum) { - foreach (ITypeReference baseTypeRef in baseTypes) { - IType baseType = baseTypeRef.Resolve(context); - if (baseType.Kind != TypeKind.Interface) - hasNonInterface = true; - yield return baseType; - } - } - if (!hasNonInterface && !(this.Name == "Object" && this.Namespace == "System" && this.TypeParameterCount == 0)) { - string primitiveBaseType; - switch (kind) { - case TypeKind.Enum: - primitiveBaseType = "Enum"; - break; - case TypeKind.Struct: - case TypeKind.Void: - primitiveBaseType = "ValueType"; - break; - case TypeKind.Delegate: - primitiveBaseType = "Delegate"; - break; - default: - primitiveBaseType = "Object"; - break; - } - IType t = context.GetTypeDefinition("System", primitiveBaseType, 0, StringComparer.Ordinal); - if (t != null) - yield return t; - } - } - - public virtual IList Parts { - get { - return new ITypeDefinitionPart[] { this }; - } - } - - IType ITypeReference.Resolve(ITypeResolveContext context) - { - if (context == null) - throw new ArgumentNullException("context"); - return this; - } - - ITypeDefinition IType.GetDefinition() - { - return this; - } - - public ITypeDefinition GetCompoundTypeDefinition(ITypeResolveContext context) - { - ITypeDefinition typeDef = context.GetTypeDefinition(this.Namespace, this.Name, this.TypeParameterCount, StringComparer.Ordinal); - if (typeDef != null && typeDef.Parts.Contains(this)) - return typeDef; - else - return null; - } - - #region GetMembers - public IEnumerable GetNestedTypes(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - const GetMemberOptions opt = GetMemberOptions.IgnoreInheritedMembers | GetMemberOptions.ReturnMemberDefinitions; - if ((options & opt) == opt) { - return ApplyFilter(this.NestedTypes, filter); - } else { - return GetMembersHelper.GetNestedTypes(this, context, filter, options); - } - } - - public IEnumerable GetNestedTypes(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - return GetMembersHelper.GetNestedTypes(this, typeArguments, context, filter, options); - } - - public virtual IEnumerable GetMethods(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { - return ApplyFilter(this.Methods, Utils.ExtensionMethods.And(m => !m.IsConstructor, filter)); - } else { - return GetMembersHelper.GetMethods(this, context, filter, options); - } - } - - public virtual IEnumerable GetMethods(IList typeArguments, ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - return GetMembersHelper.GetMethods(this, typeArguments, context, filter, options); - } - - public virtual IEnumerable GetConstructors(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers) - { - if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { - return GetConstructorsImpl(filter); - } else { - return GetMembersHelper.GetConstructors(this, context, filter, options); - } - } - - IEnumerable GetConstructorsImpl(Predicate filter) - { - bool foundCtor = false; - foreach (IMethod m in this.Methods) { - if (m.IsConstructor && !m.IsStatic) { - foundCtor = true; - if (filter == null || filter(m)) { - yield return m; - } - } - } - - if (this.AddDefaultConstructorIfRequired) { - if (kind == TypeKind.Class && !foundCtor && !this.IsStatic - || kind == TypeKind.Enum || kind == TypeKind.Struct) - { - var m = DefaultMethod.CreateDefaultConstructor(this); - if (filter == null || filter(m)) - yield return m; - } - } - } - - public virtual IEnumerable GetProperties(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { - return ApplyFilter(this.Properties, filter); - } else { - return GetMembersHelper.GetProperties(this, context, filter, options); - } - } - - public virtual IEnumerable GetFields(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { - return ApplyFilter(this.Fields, filter); - } else { - return GetMembersHelper.GetFields(this, context, filter, options); - } - } - - public virtual IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) { - return ApplyFilter(this.Events, filter); - } else { - return GetMembersHelper.GetEvents(this, context, filter, options); - } - } - - public virtual IEnumerable GetMembers(ITypeResolveContext context, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) - { - return GetMembersHelper.GetMembers(this, context, filter, options); - } - - static IEnumerable ApplyFilter(IList enumerable, Predicate filter) where T : class - { - if (enumerable.Count == 0) - return EmptyList.Instance; - if (filter == null) - return enumerable; - else - return ApplyFilterImpl(enumerable, filter); - } - - static IEnumerable ApplyFilterImpl(IList enumerable, Predicate filter) where T : class - { - foreach (T item in enumerable) - if (filter(item)) - yield return item; - } - #endregion - - #region Equals / GetHashCode - bool IEquatable.Equals(IType other) - { - // Use reference equality for ITypeDefinitions: - // We do not want to consider different versions of the same type as equal. - return this == other; - } - #endregion - - public override string ToString() - { - return ReflectionName; - } - - /// - /// Gets whether a default constructor should be added to this class if it is required. - /// Such automatic default constructors will not appear in ITypeDefinition.Methods, but will be present - /// in IType.GetMethods(). - /// - /// This way of creating the default constructor is necessary because - /// we cannot create it directly in the IClass - we need to consider partial classes. - public bool AddDefaultConstructorIfRequired { - get { return flags[FlagAddDefaultConstructorIfRequired]; } - set { - CheckBeforeMutation(); - flags[FlagAddDefaultConstructorIfRequired] = value; - } - } - - public IType AcceptVisitor(TypeVisitor visitor) - { - return visitor.VisitTypeDefinition(this); - } - - public IType VisitChildren(TypeVisitor visitor) - { - return this; - } - } - */ -} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs index c9402e63fa..9e9d0d2ecb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @@ -19,7 +19,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Runtime.Serialization; +using System.Threading; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem.Implementation { @@ -29,49 +33,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation [Serializable] public class DefaultUnresolvedAssembly : AbstractFreezable, IUnresolvedAssembly { - #region FullNameAndTypeParameterCount - struct FullNameAndTypeParameterCount - { - public readonly string Namespace; - public readonly string Name; - public readonly int TypeParameterCount; - - public FullNameAndTypeParameterCount(string nameSpace, string name, int typeParameterCount) - { - this.Namespace = nameSpace; - this.Name = name; - this.TypeParameterCount = typeParameterCount; - } - } - - sealed class FullNameAndTypeParameterCountComparer : IEqualityComparer - { - public static readonly FullNameAndTypeParameterCountComparer Ordinal = new FullNameAndTypeParameterCountComparer(StringComparer.Ordinal); - - public readonly StringComparer NameComparer; - - public FullNameAndTypeParameterCountComparer(StringComparer nameComparer) - { - this.NameComparer = nameComparer; - } - - public bool Equals(FullNameAndTypeParameterCount x, FullNameAndTypeParameterCount y) - { - return x.TypeParameterCount == y.TypeParameterCount - && NameComparer.Equals(x.Name, y.Name) - && NameComparer.Equals(x.Namespace, y.Namespace); - } - - public int GetHashCode(FullNameAndTypeParameterCount obj) - { - return NameComparer.GetHashCode(obj.Name) ^ NameComparer.GetHashCode(obj.Namespace) ^ obj.TypeParameterCount; - } - } - #endregion - string assemblyName; - IList assemblyAttributes = new List(); - IList moduleAttributes = new List(); + IList assemblyAttributes; + IList moduleAttributes; Dictionary typeDefinitions = new Dictionary(FullNameAndTypeParameterCountComparer.Ordinal); protected override void FreezeInternal() @@ -89,6 +53,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (assemblyName == null) throw new ArgumentNullException("assemblyName"); this.assemblyName = assemblyName; + this.assemblyAttributes = new List(); + this.moduleAttributes = new List(); } public string AssemblyName { @@ -167,18 +133,95 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return "[" + GetType().Name + " " + assemblyName + "]"; } - sealed class DefaultResolvedAssembly : IAssembly, ITypeResolveContext + //[NonSerialized] + //List> cachedTypeDictionariesPerNameComparer; + + Dictionary GetTypeDictionary(StringComparer nameComparer) + { + Debug.Assert(IsFrozen); + if (nameComparer == StringComparer.Ordinal) + return typeDefinitions; + else + throw new NotImplementedException(); + } + + #region UnresolvedNamespace + sealed class UnresolvedNamespace + { + internal readonly string FullName; + internal readonly string Name; + internal readonly List Children = new List(); + + public UnresolvedNamespace(string fullName, string name) + { + this.FullName = fullName; + this.Name = name; + } + } + + [NonSerialized] + List> unresolvedNamespacesPerNameComparer; + + UnresolvedNamespace GetUnresolvedRootNamespace(StringComparer nameComparer) + { + Debug.Assert(IsFrozen); + LazyInitializer.EnsureInitialized(ref unresolvedNamespacesPerNameComparer); + lock (unresolvedNamespacesPerNameComparer) { + foreach (var pair in unresolvedNamespacesPerNameComparer) { + if (pair.Key == nameComparer) + return pair.Value; + } + var root = new UnresolvedNamespace(string.Empty, string.Empty); + var dict = new Dictionary(nameComparer); + dict.Add(root.FullName, root); + foreach (var typeName in typeDefinitions.Keys) { + GetOrAddNamespace(dict, typeName.Namespace); + } + unresolvedNamespacesPerNameComparer.Add(new KeyValuePair(nameComparer, root)); + return root; + } + } + + static UnresolvedNamespace GetOrAddNamespace(Dictionary dict, string fullName) + { + UnresolvedNamespace ns; + if (dict.TryGetValue(fullName, out ns)) + return ns; + int pos = fullName.LastIndexOf('.'); + UnresolvedNamespace parent; + string name; + if (pos < 0) { + parent = dict[string.Empty]; // root + name = fullName; + } else { + parent = GetOrAddNamespace(dict, fullName.Substring(0, pos)); + name = fullName.Substring(pos + 1); + } + ns = new UnresolvedNamespace(fullName, name); + parent.Children.Add(ns); + dict.Add(fullName, ns); + return ns; + } + #endregion + + sealed class DefaultResolvedAssembly : IAssembly { readonly DefaultUnresolvedAssembly unresolved; readonly ICompilation compilation; + readonly ITypeResolveContext context; + readonly Dictionary unresolvedTypeDict; readonly ConcurrentDictionary typeDict = new ConcurrentDictionary(); + readonly INamespace rootNamespace; public DefaultResolvedAssembly(ICompilation compilation, DefaultUnresolvedAssembly unresolved) { this.compilation = compilation; this.unresolved = unresolved; - this.AssemblyAttributes = unresolved.AssemblyAttributes.ToList().CreateResolvedAttributes(this); - this.ModuleAttributes = unresolved.ModuleAttributes.ToList().CreateResolvedAttributes(this); + this.unresolvedTypeDict = unresolved.GetTypeDictionary(compilation.NameComparer); + this.rootNamespace = new NS(this, unresolved.GetUnresolvedRootNamespace(compilation.NameComparer), null); + this.context = new SimpleTypeResolveContext(this); + this.AssemblyAttributes = unresolved.AssemblyAttributes.ToList().CreateResolvedAttributes(context); + this.ModuleAttributes = unresolved.ModuleAttributes.ToList().CreateResolvedAttributes(context); } public IUnresolvedAssembly UnresolvedAssembly { @@ -197,9 +240,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IList ModuleAttributes { get; private set; } public INamespace RootNamespace { - get { - throw new NotImplementedException(); - } + get { return rootNamespace; } } public ICompilation Compilation { @@ -227,24 +268,79 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { if (unresolved.DeclaringTypeDefinition != null) { ITypeDefinition declaringType = GetTypeDefinition(unresolved.DeclaringTypeDefinition); - return new DefaultResolvedTypeDefinition(new SimpleTypeResolveContext(declaringType), unresolved); + return new DefaultResolvedTypeDefinition(context.WithCurrentTypeDefinition(declaringType), unresolved); } else if (unresolved.Name == "Void" && unresolved.Namespace == "System" && unresolved.TypeParameters.Count == 0) { - return new VoidTypeDefinition(this, unresolved); + return new VoidTypeDefinition(context, unresolved); } else { - return new DefaultResolvedTypeDefinition(this, unresolved); + return new DefaultResolvedTypeDefinition(context, unresolved); } } - IAssembly ITypeResolveContext.CurrentAssembly { - get { return this; } - } - - ITypeDefinition ITypeResolveContext.CurrentTypeDefinition { - get { return null; } - } - - IMember ITypeResolveContext.CurrentMember { - get { return null; } + sealed class NS : INamespace + { + readonly DefaultResolvedAssembly assembly; + readonly UnresolvedNamespace ns; + readonly INamespace parentNamespace; + readonly IList childNamespaces; + + public NS(DefaultResolvedAssembly assembly, UnresolvedNamespace ns, INamespace parentNamespace) + { + this.assembly = assembly; + this.ns = ns; + this.parentNamespace = parentNamespace; + this.childNamespaces = new ProjectedList( + this, ns.Children, (self, c) => new NS(self.assembly, c, self)); + } + + string INamespace.ExternAlias { + get { return null; } + } + + string INamespace.FullName { + get { return ns.FullName; } + } + + string INamespace.Name { + get { return ns.Name; } + } + + INamespace INamespace.ParentNamespace { + get { return parentNamespace; } + } + + IEnumerable INamespace.ChildNamespaces { + get { return childNamespaces; } + } + + INamespace INamespace.GetChildNamespace(string name) + { + var nameComparer = assembly.compilation.NameComparer; + for (int i = 0; i < childNamespaces.Count; i++) { + if (nameComparer.Equals(name, ns.Children[i].Name)) + return childNamespaces[i]; + } + return null; + } + + ICompilation IResolved.Compilation { + get { return assembly.compilation; } + } + + IEnumerable INamespace.Types { + get { + throw new NotImplementedException(); + } + } + + ITypeDefinition INamespace.GetTypeDefinition(string name, int typeParameterCount) + { + var key = new FullNameAndTypeParameterCount(ns.FullName, name, typeParameterCount); + IUnresolvedTypeDefinition unresolvedTypeDef; + if (assembly.unresolvedTypeDict.TryGetValue(key, out unresolvedTypeDef)) + return assembly.GetTypeDefinition(unresolvedTypeDef); + else + return null; + } } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs index 04a55eb22e..c0226682f2 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedAttribute.cs @@ -26,6 +26,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// Default implementation of . /// + [Serializable] public sealed class DefaultUnresolvedAttribute : AbstractFreezable, IUnresolvedAttribute, IFreezable, ISupportsInterning { ITypeReference attributeType; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs index c1c9834648..f2aacd9dee 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultUnresolvedTypeDefinition.cs @@ -141,7 +141,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("context"); if (context.CurrentAssembly == null) throw new ArgumentException("An ITypeDefinition cannot be resolved in a context without a current assembly."); - return context.CurrentAssembly.GetTypeDefinition(this); + return context.CurrentAssembly.GetTypeDefinition(this) ?? (IType)SpecialType.UnknownType; + } + + public virtual ITypeResolveContext CreateResolveContext(ITypeResolveContext parentContext) + { + return parentContext; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs new file mode 100644 index 0000000000..0e3351187c --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/FullNameAndTypeParameterCount.cs @@ -0,0 +1,64 @@ +// Copyright (c) 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; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Serializable] + public struct FullNameAndTypeParameterCount + { + public readonly string Namespace; + public readonly string Name; + public readonly int TypeParameterCount; + + public FullNameAndTypeParameterCount(string nameSpace, string name, int typeParameterCount) + { + this.Namespace = nameSpace; + this.Name = name; + this.TypeParameterCount = typeParameterCount; + } + } + + [Serializable] + public sealed class FullNameAndTypeParameterCountComparer : IEqualityComparer + { + public static readonly FullNameAndTypeParameterCountComparer Ordinal = new FullNameAndTypeParameterCountComparer(StringComparer.Ordinal); + public static readonly FullNameAndTypeParameterCountComparer OrdinalIgnoreCase = new FullNameAndTypeParameterCountComparer(StringComparer.OrdinalIgnoreCase); + + public readonly StringComparer NameComparer; + + public FullNameAndTypeParameterCountComparer(StringComparer nameComparer) + { + this.NameComparer = nameComparer; + } + + public bool Equals(FullNameAndTypeParameterCount x, FullNameAndTypeParameterCount y) + { + return x.TypeParameterCount == y.TypeParameterCount + && NameComparer.Equals(x.Name, y.Name) + && NameComparer.Equals(x.Namespace, y.Namespace); + } + + public int GetHashCode(FullNameAndTypeParameterCount obj) + { + return NameComparer.GetHashCode(obj.Name) ^ NameComparer.GetHashCode(obj.Namespace) ^ obj.TypeParameterCount; + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs new file mode 100644 index 0000000000..349ebbf850 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/MergedNamespace.cs @@ -0,0 +1,146 @@ +// Copyright (c) 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 System.Linq; +using System.Text; +using ICSharpCode.NRefactory.Utils; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + /// + /// A merged namespace. + /// + public sealed class MergedNamespace : INamespace + { + readonly string externAlias; + readonly ICompilation compilation; + readonly INamespace parentNamespace; + readonly INamespace[] namespaces; + Dictionary childNamespaces; + + /// + /// Creates a new merged root namespace. + /// + /// The individual namespaces being merged. + /// The extern alias for this namespace. + public MergedNamespace(ICompilation compilation, INamespace[] namespaces, string externAlias = null) + { + if (compilation == null) + throw new ArgumentNullException("compilation"); + if (namespaces == null) + throw new ArgumentNullException("namespaces"); + this.compilation = compilation; + this.namespaces = namespaces; + this.externAlias = externAlias; + } + + /// + /// Creates a new merged child namespace. + /// + /// The parent merged namespace. + /// The individual namespaces being merged. + public MergedNamespace(INamespace parentNamespace, INamespace[] namespaces) + { + if (parentNamespace == null) + throw new ArgumentNullException("parentNamespace"); + if (namespaces == null) + throw new ArgumentNullException("namespaces"); + this.parentNamespace = parentNamespace; + this.namespaces = namespaces; + this.compilation = parentNamespace.Compilation; + this.externAlias = parentNamespace.ExternAlias; + } + + public string ExternAlias { + get { return externAlias; } + } + + public string FullName { + get { return namespaces[0].FullName; } + } + + public string Name { + get { return namespaces[0].Name; } + } + + public INamespace ParentNamespace { + get { return parentNamespace; } + } + + public IEnumerable Types { + get { + return namespaces.SelectMany(ns => ns.Types); + } + } + + public ICompilation Compilation { + get { return compilation; } + } + + public IEnumerable ChildNamespaces { + get { return GetChildNamespaces().Values; } + } + + public INamespace GetChildNamespace(string name) + { + INamespace ns; + if (GetChildNamespaces().TryGetValue(name, out ns)) + return ns; + else + return null; + } + + Dictionary GetChildNamespaces() + { + var result = this.childNamespaces; + if (result != null) { + LazyInit.ReadBarrier(); + return result; + } else { + result = new Dictionary(compilation.NameComparer); + foreach (var g in namespaces.SelectMany(ns => ns.ChildNamespaces).GroupBy(ns => ns.Name, compilation.NameComparer)) { + result.Add(g.Key, new MergedNamespace(this, g.ToArray())); + } + return LazyInit.GetOrSet(ref this.childNamespaces, result); + } + } + + public ITypeDefinition GetTypeDefinition(string name, int typeParameterCount) + { + ITypeDefinition anyTypeDef = null; + foreach (var ns in namespaces) { + ITypeDefinition typeDef = ns.GetTypeDefinition(name, typeParameterCount); + if (typeDef != null) { + if (typeDef.IsPublic || (typeDef.IsInternal && typeDef.ParentAssembly.InternalsVisibleTo(compilation.MainAssembly))) { + // Prefer accessible types over non-accessible types. + return typeDef; + } + anyTypeDef = typeDef; + } + } + return anyTypeDef; + } + + public override string ToString() + { + return string.Format("[MergedNamespace {0}{1} (from {2} assemblies)]", externAlias != null ? externAlias + "::" : null, this.FullName, this.namespaces.Length); + } + } +} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs index 4618e53234..4e0a7fece5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs @@ -34,6 +34,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation readonly KnownTypeCache knownTypeCache; readonly IAssembly mainAssembly; readonly IList referencedAssemblies; + INamespace rootNamespace; public SimpleCompilation(IUnresolvedAssembly mainAssembly, params IAssemblyReference[] assemblyReferences) : this(mainAssembly, (IEnumerable)assemblyReferences) @@ -55,11 +56,19 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } public IAssembly MainAssembly { - get { return mainAssembly; } + get { + if (mainAssembly == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return mainAssembly; + } } public IList ReferencedAssemblies { - get { return referencedAssemblies; } + get { + if (referencedAssemblies == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return referencedAssemblies; + } } public ITypeResolveContext TypeResolveContext { @@ -68,8 +77,26 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public INamespace RootNamespace { get { - throw new NotImplementedException(); + INamespace ns = this.rootNamespace; + if (ns != null) { + LazyInit.ReadBarrier(); + return ns; + } else { + if (referencedAssemblies == null) + throw new InvalidOperationException("Compilation isn't initialized yet"); + return LazyInit.GetOrSet(ref this.rootNamespace, CreateRootNamespace()); + } + } + } + + protected virtual INamespace CreateRootNamespace() + { + INamespace[] namespaces = new INamespace[referencedAssemblies.Count + 1]; + namespaces[0] = mainAssembly.RootNamespace; + for (int i = 0; i < referencedAssemblies.Count; i++) { + namespaces[i + 1] = referencedAssemblies[i].RootNamespace; } + return new MergedNamespace(this, namespaces); } public CacheManager CacheManager { @@ -91,5 +118,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { return knownTypeCache.FindType(typeCode); } + + public StringComparer NameComparer { + get { return StringComparer.Ordinal; } + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs deleted file mode 100644 index 1060fab5db..0000000000 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleProjectContent.cs +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) 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 System.Collections.ObjectModel; -using System.Linq; -using System.Runtime.Serialization; -using System.Threading; -using ICSharpCode.NRefactory.Utils; - -namespace ICSharpCode.NRefactory.TypeSystem.Implementation -{ - /* - /// - /// Simple implementation that stores the list of classes/namespaces. - /// Synchronization is implemented using a . - /// - /// - /// Compared with , this class adds support for the IProjectContent interface, - /// for partial classes, and for multi-threading. - /// - [Serializable] - public class SimpleProjectContent : AbstractAnnotatable, IProjectContent, ISerializable, IDeserializationCallback - { - readonly TypeStorage types = new TypeStorage(); - readonly ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - readonly Dictionary fileDict = new Dictionary(Platform.FileNameComparer); - - #region Constructor - /// - /// Creates a new SimpleProjectContent instance. - /// - public SimpleProjectContent() - { - } - #endregion - - public virtual string AssemblyName { - get { return string.Empty; } - } - - #region AssemblyAttributes - readonly List assemblyAttributes = new List(); // mutable assembly attribute storage - readonly List moduleAttributes = new List(); - - volatile IAttribute[] readOnlyAssemblyAttributes = {}; // volatile field with copy for reading threads - volatile IAttribute[] readOnlyModuleAttributes = {}; - - /// - public IList AssemblyAttributes { - get { return readOnlyAssemblyAttributes; } - } - - /// - public IList ModuleAttributes { - get { return readOnlyModuleAttributes; } - } - - static bool AddRemoveAttributes(ICollection removedAttributes, ICollection addedAttributes, - List attributeStorage) - { - // API uses ICollection instead of IEnumerable to discourage users from evaluating - // the list inside the lock (this method is called inside the write lock) - // [[not an issue anymore; the user now passes IParsedFile]] - bool hasChanges = false; - if (removedAttributes != null && removedAttributes.Count > 0) { - if (attributeStorage.RemoveAll(removedAttributes.Contains) > 0) - hasChanges = true; - } - if (addedAttributes != null) { - attributeStorage.AddRange(addedAttributes); - hasChanges = true; - } - return hasChanges; - } - - void AddRemoveAssemblyAttributes(ICollection removedAttributes, ICollection addedAttributes) - { - if (AddRemoveAttributes(removedAttributes, addedAttributes, assemblyAttributes)) - readOnlyAssemblyAttributes = assemblyAttributes.ToArray(); - } - - void AddRemoveModuleAttributes(ICollection removedAttributes, ICollection addedAttributes) - { - if (AddRemoveAttributes(removedAttributes, addedAttributes, moduleAttributes)) - readOnlyModuleAttributes = moduleAttributes.ToArray(); - } - #endregion - - #region AddType - void AddType(ITypeDefinition typeDefinition) - { - if (typeDefinition == null) - throw new ArgumentNullException("typeDefinition"); - if (typeDefinition.ProjectContent != this) - throw new ArgumentException("Cannot add a type definition that belongs to another project content"); - - ITypeDefinition existingTypeDef = types.GetTypeDefinition(typeDefinition.Namespace, typeDefinition.Name, typeDefinition.TypeParameterCount, StringComparer.Ordinal); - if (existingTypeDef != null) { - // Add a part to a compound class - var newParts = new List(existingTypeDef.GetParts()); - newParts.Add(typeDefinition); - types.UpdateType(CompoundTypeDefinition.Create(newParts)); - } else { - types.UpdateType(typeDefinition); - } - } - #endregion - - #region RemoveType - void RemoveType(ITypeDefinition typeDefinition) - { - var compoundTypeDef = typeDefinition.GetDefinition() as CompoundTypeDefinition; - if (compoundTypeDef != null) { - // Remove one part from a compound class - var newParts = new List(compoundTypeDef.GetParts()); - // We cannot use newParts.Remove() because we need to use reference equality - for (int i = 0; i < newParts.Count; i++) { - if (newParts[i] == typeDefinition) { - newParts.RemoveAt(i); - ((DefaultTypeDefinition)typeDefinition).SetCompoundTypeDefinition(typeDefinition); - break; - } - } - types.UpdateType(CompoundTypeDefinition.Create(newParts)); - } else { - types.RemoveType(typeDefinition); - } - } - #endregion - - #region UpdateProjectContent - /// - /// Removes types and attributes from oldFile from the project, and adds those from newFile. - /// - /// - /// The update is done inside a write lock; when other threads access this project content - /// from within a using (Synchronize()) block, they will not see intermediate (inconsistent) state. - /// - public void UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile) - { - if (oldFile != null && newFile != null) { - if (!Platform.FileNameComparer.Equals(oldFile.FileName, newFile.FileName)) - throw new ArgumentException("When both oldFile and newFile are specified, they must use the same file name."); - } - readerWriterLock.EnterWriteLock(); - try { - if (oldFile != null) { - foreach (var element in oldFile.TopLevelTypeDefinitions) { - RemoveType(element); - } - if (newFile == null) { - fileDict.Remove(oldFile.FileName); - } - } - if (newFile != null) { - foreach (var element in newFile.TopLevelTypeDefinitions) { - AddType(element); - } - fileDict[newFile.FileName] = newFile; - } - AddRemoveAssemblyAttributes(oldFile != null ? oldFile.AssemblyAttributes : null, - newFile != null ? newFile.AssemblyAttributes : null); - - AddRemoveModuleAttributes(oldFile != null ? oldFile.ModuleAttributes : null, - newFile != null ? newFile.ModuleAttributes : null); - } finally { - readerWriterLock.ExitWriteLock(); - } - } - #endregion - - #region IProjectContent implementation - public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode) - { - readerWriterLock.EnterReadLock(); - try { - return types.GetKnownTypeDefinition(typeCode); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer) - { - readerWriterLock.EnterReadLock(); - try { - return types.GetTypeDefinition(nameSpace, name, typeParameterCount, nameComparer); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public IEnumerable GetTypes() - { - readerWriterLock.EnterReadLock(); - try { - // make a copy with ToArray() for thread-safe access - return types.GetTypes().ToArray(); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public IEnumerable GetTypes(string nameSpace, StringComparer nameComparer) - { - readerWriterLock.EnterReadLock(); - try { - // make a copy with ToArray() for thread-safe access - return types.GetTypes(nameSpace, nameComparer).ToArray(); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public IEnumerable GetNamespaces() - { - readerWriterLock.EnterReadLock(); - try { - // make a copy with ToArray() for thread-safe access - return types.GetNamespaces().ToArray(); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public string GetNamespace(string nameSpace, StringComparer nameComparer) - { - readerWriterLock.EnterReadLock(); - try { - return types.GetNamespace(nameSpace, nameComparer); - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public IParsedFile GetFile(string fileName) - { - readerWriterLock.EnterReadLock(); - try { - IParsedFile file; - if (fileDict.TryGetValue(fileName, out file)) - return file; - else - return null; - } finally { - readerWriterLock.ExitReadLock(); - } - } - - public IEnumerable Files { - get { - readerWriterLock.EnterReadLock(); - try { - return fileDict.Values.ToArray(); - } finally { - readerWriterLock.ExitReadLock(); - } - } - } - #endregion - - #region Synchronization - public CacheManager CacheManager { - get { return null; } - } - - public ISynchronizedTypeResolveContext Synchronize() - { - // don't acquire the lock on OutOfMemoryException etc. - ISynchronizedTypeResolveContext sync = new ReadWriteSynchronizedTypeResolveContext(types, readerWriterLock); - readerWriterLock.EnterReadLock(); - return sync; - } - - sealed class ReadWriteSynchronizedTypeResolveContext : ProxyTypeResolveContext, ISynchronizedTypeResolveContext - { - ReaderWriterLockSlim readerWriterLock; - - public ReadWriteSynchronizedTypeResolveContext(ITypeResolveContext target, ReaderWriterLockSlim readerWriterLock) - : base(target) - { - this.readerWriterLock = readerWriterLock; - } - - public void Dispose() - { - if (readerWriterLock != null) { - readerWriterLock.ExitReadLock(); - readerWriterLock = null; - } - } - - public override ISynchronizedTypeResolveContext Synchronize() - { - // nested Synchronize() calls don't need any locking - return new ReadWriteSynchronizedTypeResolveContext(target, null); - } - } - #endregion - - #region Serialization - SerializationInfo serializationInfo; - - protected SimpleProjectContent(SerializationInfo info, StreamingContext context) - { - this.serializationInfo = info; - assemblyAttributes.AddRange((IAttribute[])info.GetValue("AssemblyAttributes", typeof(IAttribute[]))); - readOnlyAssemblyAttributes = assemblyAttributes.ToArray(); - moduleAttributes.AddRange((IAttribute[])info.GetValue("ModuleAttributes", typeof(IAttribute[]))); - readOnlyModuleAttributes = moduleAttributes.ToArray(); - } - - public virtual void OnDeserialization(object sender) - { - // We need to do this in OnDeserialization because at the time the deserialization - // constructor runs, type.FullName/file.FileName may not be deserialized yet. - if (serializationInfo != null) { - foreach (var typeDef in (ITypeDefinition[])serializationInfo.GetValue("Types", typeof(ITypeDefinition[]))) { - types.UpdateType(typeDef); - } - foreach (IParsedFile file in (IParsedFile[])serializationInfo.GetValue("Files", typeof(IParsedFile[]))) { - fileDict.Add(file.FileName, file); - } - serializationInfo = null; - } - } - - public virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - readerWriterLock.EnterReadLock(); - try { - info.AddValue("Types", types.GetTypes().ToArray()); - info.AddValue("AssemblyAttributes", readOnlyAssemblyAttributes); - info.AddValue("ModuleAttributes", readOnlyModuleAttributes); - info.AddValue("Files", fileDict.Values.ToArray()); - } finally { - readerWriterLock.ExitReadLock(); - } - } - #endregion - } - */ -} diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs index c792753e89..4edf4ea6fb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleTypeResolveContext.cs @@ -64,6 +64,14 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation this.currentMember = member; } + private SimpleTypeResolveContext(ICompilation compilation, IAssembly currentAssembly, ITypeDefinition currentTypeDefinition, IMember currentMember) + { + this.compilation = compilation; + this.currentAssembly = currentAssembly; + this.currentTypeDefinition = currentTypeDefinition; + this.currentMember = currentMember; + } + public ICompilation Compilation { get { return compilation; } } @@ -79,5 +87,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IMember CurrentMember { get { return currentMember; } } + + public ITypeResolveContext WithCurrentTypeDefinition(ITypeDefinition typeDefinition) + { + return new SimpleTypeResolveContext(compilation, currentAssembly, typeDefinition, currentMember); + } + + public ITypeResolveContext WithCurrentMember(IMember member) + { + return new SimpleTypeResolveContext(compilation, currentAssembly, currentTypeDefinition, member); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterReference.cs index 123f56e00f..79aa3cbdd5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/TypeParameterReference.cs @@ -62,5 +62,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation TypeParameterReference r = other as TypeParameterReference; return r != null && index == r.index && ownerType == r.ownerType; } + + public override string ToString() + { + if (ownerType == EntityType.Method) + return "!!" + index.ToString(); + else + return "!" + index.ToString(); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs b/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs index 9ce7cfb7ff..61aa6c5ebe 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ParameterListComparer.cs @@ -39,12 +39,11 @@ namespace ICSharpCode.NRefactory.TypeSystem // In order to compare the method signatures, we will normalize all method type parameters. sealed class NormalizeMethodTypeParameters : TypeVisitor { - //ITypeParameter[] normalTypeParameters = { new DefaultTypeParameter(EntityType.Method, 0, string.Empty) }; + ITypeParameter[] normalTypeParameters = { new DefaultTypeParameter(EntityType.Method, 0) }; public override IType VisitTypeParameter(ITypeParameter type) { - throw new NotImplementedException(); - /*if (type.OwnerType == EntityType.Method) { + if (type.OwnerType == EntityType.Method) { ITypeParameter[] tps = this.normalTypeParameters; while (type.Index >= tps.Length) { // We don't have a normal type parameter for this index, so we need to extend our array. @@ -53,7 +52,7 @@ namespace ICSharpCode.NRefactory.TypeSystem ITypeParameter[] newTps = new ITypeParameter[type.Index + 1]; tps.CopyTo(newTps, 0); for (int i = tps.Length; i < newTps.Length; i++) { - newTps[i] = new DefaultTypeParameter(EntityType.Method, i, string.Empty); + newTps[i] = new DefaultTypeParameter(EntityType.Method, i); } ITypeParameter[] oldTps = Interlocked.CompareExchange(ref normalTypeParameters, newTps, tps); if (oldTps == tps) { @@ -67,7 +66,7 @@ namespace ICSharpCode.NRefactory.TypeSystem return tps[type.Index]; } else { return base.VisitTypeParameter(type); - }*/ + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs b/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs index d3666b2c2c..dae398ddf4 100644 --- a/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs +++ b/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs @@ -84,9 +84,12 @@ namespace ICSharpCode.NRefactory.TypeSystem return this; } - [ObsoleteAttribute] + #pragma warning disable 809 + [Obsolete("Please compare special types using the kind property instead.")] public override bool Equals(IType other) { + // We consider a special types equal when they have equal types. + // However, an unknown type with additional information is not considered to be equal to the SpecialType with TypeKind.Unknown. return other is SpecialType && other.Kind == kind; } diff --git a/ICSharpCode.NRefactory/Utils/FastSerializer.cs b/ICSharpCode.NRefactory/Utils/FastSerializer.cs index 9a14c03315..bae01a6526 100644 --- a/ICSharpCode.NRefactory/Utils/FastSerializer.cs +++ b/ICSharpCode.NRefactory/Utils/FastSerializer.cs @@ -546,7 +546,7 @@ namespace ICSharpCode.NRefactory.Utils context.WriteObjectID(val); } }; - } else if (type == typeof(byte[])) { + } else if (type == typeof(byte)) { return delegate (SerializationContext context, object array) { context.writer.Write((byte[])array); }; @@ -1020,7 +1020,7 @@ namespace ICSharpCode.NRefactory.Utils array[i] = context.ReadObject(); } }; - } else if (type == typeof(byte[])) { + } else if (type == typeof(byte)) { return delegate (DeserializationContext context, object arrayInstance) { byte[] array = (byte[])arrayInstance; BinaryReader binaryReader = context.Reader; @@ -1080,7 +1080,7 @@ namespace ICSharpCode.NRefactory.Utils Debug.Assert(type.IsPrimitive); il.Emit(OpCodes.Ldloc, instance); // instance il.Emit(OpCodes.Ldloc, loopVariable); // instance, loopVariable - EmitReadValueType(il, reader, type); // instance, loopVariable, value + ReadPrimitiveValue(il, reader, type); // instance, loopVariable, value switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: case TypeCode.SByte: diff --git a/ICSharpCode.NRefactory/Utils/ProjectedList.cs b/ICSharpCode.NRefactory/Utils/ProjectedList.cs index b5df19f0d9..beacd3d155 100644 --- a/ICSharpCode.NRefactory/Utils/ProjectedList.cs +++ b/ICSharpCode.NRefactory/Utils/ProjectedList.cs @@ -106,12 +106,14 @@ namespace ICSharpCode.NRefactory.Utils void ICollection.CopyTo(TOutput[] array, int arrayIndex) { - throw new NotImplementedException(); + for (int i = 0; i < items.Length; i++) { + array[arrayIndex + i] = this[i]; + } } bool ICollection.Remove(TOutput item) { - throw new NotImplementedException(); + throw new NotSupportedException(); } public IEnumerator GetEnumerator() @@ -214,12 +216,128 @@ namespace ICSharpCode.NRefactory.Utils void ICollection.CopyTo(TOutput[] array, int arrayIndex) { - throw new NotImplementedException(); + for (int i = 0; i < items.Length; i++) { + array[arrayIndex + i] = this[i]; + } + } + + bool ICollection.Remove(TOutput item) + { + throw new NotSupportedException(); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) { + yield return this[i]; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public sealed class ProjectedListWithContextPerElement : IList where TOutput : class + { + readonly IList input; + readonly IList context; + readonly Func projection; + readonly TOutput[] items; + + public ProjectedListWithContextPerElement(IList context, IList input, Func projection) + { + if (context == null) + throw new ArgumentNullException("context"); + if (input == null) + throw new ArgumentNullException("input"); + if (projection == null) + throw new ArgumentNullException("projection"); + if (context.Count != input.Count) + throw new ArgumentException("context list must have same length as input list"); + this.input = input; + this.context = context; + this.projection = projection; + this.items = new TOutput[input.Count]; + } + + public TOutput this[int index] { + get { + TOutput output = items[index]; + if (output != null) { + LazyInit.ReadBarrier(); + return output; + } + return LazyInit.GetOrSet(ref items[index], projection(context[index], input[index])); + } + } + + TOutput IList.this[int index] { + get { return this[index]; } + set { + throw new NotSupportedException(); + } + } + + public int Count { + get { return items.Length; } + } + + bool ICollection.IsReadOnly { + get { return true; } + } + + int IList.IndexOf(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return i; + } + return -1; + } + + void IList.Insert(int index, TOutput item) + { + throw new NotSupportedException(); + } + + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + + void ICollection.Add(TOutput item) + { + throw new NotSupportedException(); + } + + void ICollection.Clear() + { + throw new NotSupportedException(); + } + + bool ICollection.Contains(TOutput item) + { + var comparer = EqualityComparer.Default; + for (int i = 0; i < this.Count; i++) { + if (comparer.Equals(this[i], item)) + return true; + } + return false; + } + + void ICollection.CopyTo(TOutput[] array, int arrayIndex) + { + for (int i = 0; i < items.Length; i++) { + array[arrayIndex + i] = this[i]; + } } bool ICollection.Remove(TOutput item) { - throw new NotImplementedException(); + throw new NotSupportedException(); } public IEnumerator GetEnumerator()