From 5d0fc5b83c3d4990ab6b4fb985c1d84c4321282a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 23 Nov 2006 15:12:03 +0000 Subject: [PATCH] Fixed SD2-1095: Autogenerated code for IEnumerable generic interface does not compile git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2066 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Misc/UnitTesting/Test/Utils/MockMember.cs | 21 ++++ .../Misc/UnitTesting/Test/Utils/MockMethod.cs | 15 +++ .../Commands/ClassBookmarkMenuBuilder.cs | 12 +- .../InterfaceImplementorCodeGenerator.cs | 2 +- src/Main/Base/Test/GenericResolverTests.cs | 2 +- src/Main/Base/Test/NRefactoryResolverTests.cs | 2 + src/Main/Base/Test/SearchGenericClassTests.cs | 36 ++++-- .../ICSharpCode.SharpDevelop.Dom.csproj | 1 + .../Project/Src/CecilReader.cs | 14 +++ .../Project/Src/ClassFinder.cs | 6 + .../Src/Implementations/AbstractMember.cs | 33 ++++- .../Implementations/ConstructedReturnType.cs | 12 ++ .../Src/Implementations/DefaultEvent.cs | 18 +-- .../Src/Implementations/DefaultMethod.cs | 13 +- .../Src/Implementations/DefaultProperty.cs | 12 +- .../Src/Implementations/DefaultReturnType.cs | 4 +- .../Src/Implementations/DefaultUsing.cs | 17 ++- .../ExplicitInterfaceImplementation.cs | 55 +++++++++ .../Project/Src/Interfaces/IEvent.cs | 4 - .../Project/Src/Interfaces/IMember.cs | 18 +++ .../Project/Src/Interfaces/IMethod.cs | 4 - .../Project/Src/Interfaces/IUsing.cs | 10 +- .../Project/Src/LanguageProperties.cs | 18 +++ .../ProjectContent/DefaultProjectContent.cs | 6 +- .../Project/Src/Refactoring/CodeGenerator.cs | 114 ++++++++++++++---- .../Src/ReflectionLayer/DomPersistence.cs | 34 ++++-- 26 files changed, 384 insertions(+), 99 deletions(-) create mode 100644 src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/ExplicitInterfaceImplementation.cs diff --git a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs index f04ccf330e..06c26e8e5b 100644 --- a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs +++ b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs @@ -211,5 +211,26 @@ namespace UnitTesting.Tests.Utils { throw new NotImplementedException(); } + + public IReturnType DeclaringTypeReference { + get { + throw new NotImplementedException(); + } + set { + throw new NotImplementedException(); + } + } + + public DomRegion BodyRegion { + get { + throw new NotImplementedException(); + } + } + + public IList InterfaceImplementations { + get { + throw new NotImplementedException(); + } + } } } diff --git a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs index 84876590ca..69981326be 100644 --- a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs +++ b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs @@ -262,5 +262,20 @@ namespace UnitTesting.Tests.Utils { throw new NotImplementedException(); } + + public IReturnType DeclaringTypeReference { + get { + throw new NotImplementedException(); + } + set { + throw new NotImplementedException(); + } + } + + public IList InterfaceImplementations { + get { + throw new NotImplementedException(); + } + } } } diff --git a/src/Main/Base/Project/Src/TextEditor/Commands/ClassBookmarkMenuBuilder.cs b/src/Main/Base/Project/Src/TextEditor/Commands/ClassBookmarkMenuBuilder.cs index a6395e0027..4a5bd4f4ee 100644 --- a/src/Main/Base/Project/Src/TextEditor/Commands/ClassBookmarkMenuBuilder.cs +++ b/src/Main/Base/Project/Src/TextEditor/Commands/ClassBookmarkMenuBuilder.cs @@ -174,7 +174,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands return b.ToString(); } - void AddImplementInterfaceCommandItems(List subItems, IClass c, bool explicitImpl, ModifierEnum modifier) + void AddImplementInterfaceCommandItems(List subItems, IClass c, bool explicitImpl) { CodeGenerator codeGen = c.ProjectContent.Language.CodeGenerator; IAmbience ambience = AmbienceService.CurrentAmbience; @@ -186,7 +186,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands EventHandler eh = delegate { TextEditorDocument d = new TextEditorDocument(GetDocument(c)); if (d != null) - codeGen.ImplementInterface(rtCopy, d, explicitImpl, modifier, c); + codeGen.ImplementInterface(rtCopy, d, explicitImpl, c); ParserService.ParseCurrentViewContent(); }; subItems.Add(new MenuCommand(ambience.Convert(interf), eh)); @@ -200,16 +200,14 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands if (codeGen == null) return; List subItems = new List(); if (c.ProjectContent.Language.SupportsImplicitInterfaceImplementation) { - AddImplementInterfaceCommandItems(subItems, c, false, ModifierEnum.Public); + AddImplementInterfaceCommandItems(subItems, c, false); if (subItems.Count > 0) { list.Add(new ICSharpCode.Core.Menu("${res:SharpDevelop.Refactoring.ImplementInterfaceImplicit}", subItems.ToArray())); subItems = new List(); } - - AddImplementInterfaceCommandItems(subItems, c, true, ModifierEnum.None); - } else { - AddImplementInterfaceCommandItems(subItems, c, true, ModifierEnum.Public); } + AddImplementInterfaceCommandItems(subItems, c, true); + if (subItems.Count > 0) { if (c.ProjectContent.Language.SupportsImplicitInterfaceImplementation) { list.Add(new ICSharpCode.Core.Menu("${res:SharpDevelop.Refactoring.ImplementInterfaceExplicit}", subItems.ToArray())); diff --git a/src/Main/Base/Project/Src/TextEditor/Commands/CodeGenerators/InterfaceImplementorCodeGenerator.cs b/src/Main/Base/Project/Src/TextEditor/Commands/CodeGenerators/InterfaceImplementorCodeGenerator.cs index db0c904911..6302dd50fa 100644 --- a/src/Main/Base/Project/Src/TextEditor/Commands/CodeGenerators/InterfaceImplementorCodeGenerator.cs +++ b/src/Main/Base/Project/Src/TextEditor/Commands/CodeGenerators/InterfaceImplementorCodeGenerator.cs @@ -63,7 +63,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands foreach (ClassWrapper w in items) { codeGen.ImplementInterface(nodes, w.ClassType, !currentClass.ProjectContent.Language.SupportsImplicitInterfaceImplementation, - ModifierEnum.Public, currentClass); + currentClass); } } diff --git a/src/Main/Base/Test/GenericResolverTests.cs b/src/Main/Base/Test/GenericResolverTests.cs index 244353d9c4..9ad94e6a9f 100644 --- a/src/Main/Base/Test/GenericResolverTests.cs +++ b/src/Main/Base/Test/GenericResolverTests.cs @@ -187,7 +187,7 @@ class DerivedClass : BaseClass { #region CodeCompletion inside generic classes const string genericClass = @"using System; -public class GenericClass where T : IDisposable +public class GenericClass where T : IDisposable { void Method(T par1, G par2) where G : IConvertible, IFormattable { T var1; G var2; diff --git a/src/Main/Base/Test/NRefactoryResolverTests.cs b/src/Main/Base/Test/NRefactoryResolverTests.cs index 876382ca2d..42e1869762 100644 --- a/src/Main/Base/Test/NRefactoryResolverTests.cs +++ b/src/Main/Base/Test/NRefactoryResolverTests.cs @@ -38,6 +38,7 @@ namespace ICSharpCode.SharpDevelop.Tests NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(pc); visitor.VisitCompilationUnit(p.CompilationUnit, null); visitor.Cu.FileName = fileName; + Assert.AreEqual(0, p.Errors.Count, "Parse error preparing compilation unit"); visitor.Cu.ErrorsDuringCompile = p.Errors.Count > 0; foreach (IClass c in visitor.Cu.Classes) { pc.AddClassToNamespaceList(c); @@ -64,6 +65,7 @@ namespace ICSharpCode.SharpDevelop.Tests NRefactoryASTConvertVisitor visitor = new NRefactoryASTConvertVisitor(pc); visitor.VisitCompilationUnit(p.CompilationUnit, null); visitor.Cu.FileName = fileName; + Assert.AreEqual(0, p.Errors.Count, "Parse error preparing compilation unit"); visitor.Cu.ErrorsDuringCompile = p.Errors.Count > 0; foreach (IClass c in visitor.Cu.Classes) { pc.AddClassToNamespaceList(c); diff --git a/src/Main/Base/Test/SearchGenericClassTests.cs b/src/Main/Base/Test/SearchGenericClassTests.cs index 5c6b4d8ac4..cdb61ed65a 100644 --- a/src/Main/Base/Test/SearchGenericClassTests.cs +++ b/src/Main/Base/Test/SearchGenericClassTests.cs @@ -19,18 +19,26 @@ namespace ICSharpCode.SharpDevelop.Tests ProjectContentRegistry projectContentRegistry = ParserService.DefaultProjectContentRegistry; #region Helper methods - ICompilationUnit Prepare(LanguageProperties language) + // usingMode: 0 = one using-statement for each namespace (correctly cased) + // 1 = mixture of using statements and default imports (incorrectly cased) + // 2 = all default imports (incorrectly cased) + ICompilationUnit Prepare(LanguageProperties language, int usingMode) { DefaultProjectContent pc = new DefaultProjectContent(); pc.ReferencedContents.Add(projectContentRegistry.Mscorlib); pc.Language = language; DefaultCompilationUnit cu = new DefaultCompilationUnit(pc); - if (language == LanguageProperties.VBNet) { + if (usingMode == 1) { cu.Usings.Add(CreateUsing(pc, "syStEm.coLLectIons")); pc.DefaultImports = new DefaultUsing(pc); pc.DefaultImports.Usings.Add("syStEm"); pc.DefaultImports.Usings.Add("syStEm.coLLEctionS.GeNeRic"); - } else { + } else if (usingMode == 2) { + pc.DefaultImports = new DefaultUsing(pc); + pc.DefaultImports.Usings.Add("syStEm"); + pc.DefaultImports.Usings.Add("syStEm.coLLEctioNs"); + pc.DefaultImports.Usings.Add("syStEm.coLLEctionS.GeNeRic"); + } else { // usingMode == 0 cu.Usings.Add(CreateUsing(pc, "System")); cu.Usings.Add(CreateUsing(pc, "System.Collections")); cu.Usings.Add(CreateUsing(pc, "System.Collections.Generic")); @@ -47,7 +55,7 @@ namespace ICSharpCode.SharpDevelop.Tests IReturnType SearchType(string type, int typeParameterCount) { - ICompilationUnit cu = Prepare(LanguageProperties.CSharp); + ICompilationUnit cu = Prepare(LanguageProperties.CSharp, 0); IReturnType c = cu.ProjectContent.SearchType(new SearchTypeRequest(type, typeParameterCount, null, cu, 1, 1)).Result; Assert.IsNotNull(c, type + "not found"); return c; @@ -55,10 +63,22 @@ namespace ICSharpCode.SharpDevelop.Tests IReturnType SearchTypeVB(string type, int typeParameterCount) { - ICompilationUnit cu = Prepare(LanguageProperties.VBNet); - IReturnType c = cu.ProjectContent.SearchType(new SearchTypeRequest(type, typeParameterCount, null, cu, 1, 1)).Result; - Assert.IsNotNull(c, type + "not found"); - return c; + ICompilationUnit cu; + cu = Prepare(LanguageProperties.VBNet, 0); + IReturnType c0 = cu.ProjectContent.SearchType(new SearchTypeRequest(type, typeParameterCount, null, cu, 1, 1)).Result; + Assert.IsNotNull(c0, type + "not found for mode=0"); + + cu = Prepare(LanguageProperties.VBNet, 1); + IReturnType c1 = cu.ProjectContent.SearchType(new SearchTypeRequest(type, typeParameterCount, null, cu, 1, 1)).Result; + Assert.IsNotNull(c1, type + "not found for mode=1"); + + cu = Prepare(LanguageProperties.VBNet, 2); + IReturnType c2 = cu.ProjectContent.SearchType(new SearchTypeRequest(type, typeParameterCount, null, cu, 1, 1)).Result; + Assert.IsNotNull(c2, type + "not found for mode=2"); + + Assert.IsTrue(c0.Equals(c1) && c0.Equals(c2)); + + return c0; } void CheckType(string shortName, string vbShortName, string fullType, int typeParameterCount) diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj index 459a96ac5e..5bcbb4f6bd 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/ICSharpCode.SharpDevelop.Dom.csproj @@ -83,6 +83,7 @@ + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs index a6d1836440..6c04060721 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs @@ -328,10 +328,24 @@ namespace ICSharpCode.SharpDevelop.Dom m.Modifiers = TranslateModifiers(method); } AddParameters(m, method.Parameters); + AddExplicitInterfaceImplementations(method.Overrides, m); Methods.Add(m); } } + void AddExplicitInterfaceImplementations(OverrideCollection overrides, IMember targetMember) + { + foreach (MethodReference overrideRef in overrides) { + if (overrideRef.Name == targetMember.Name && targetMember.IsPublic) { + continue; // is like implicit interface implementation / normal override + } + targetMember.InterfaceImplementations.Add(new ExplicitInterfaceImplementation( + CreateType(this.ProjectContent, targetMember, overrideRef.DeclaringType), + overrideRef.Name + )); + } + } + void AddParameters(IMethodOrProperty target, ParameterDefinitionCollection plist) { foreach (ParameterDefinition par in plist) { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ClassFinder.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ClassFinder.cs index fcd62d9f4d..4f02e68800 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ClassFinder.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ClassFinder.cs @@ -32,6 +32,12 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public LanguageProperties Language { + get { + return projectContent.Language; + } + } + public ClassFinder(string fileName, string fileContent, int offset) { caretLine = 0; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs index b56f28c7ea..7b1f55805d 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs @@ -6,13 +6,17 @@ // using System; +using System.Collections.Generic; namespace ICSharpCode.SharpDevelop.Dom { public abstract class AbstractMember : AbstractNamedEntity, IMember { IReturnType returnType; - DomRegion region; + DomRegion region; + DomRegion bodyRegion; + List interfaceImplementations; + IReturnType declaringTypeReference; public virtual DomRegion Region { get { @@ -23,6 +27,15 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public virtual DomRegion BodyRegion { + get { + return bodyRegion; + } + protected set { + bodyRegion = value; + } + } + public virtual IReturnType ReturnType { get { return returnType; @@ -32,6 +45,24 @@ namespace ICSharpCode.SharpDevelop.Dom } } + /// + /// Gets the declaring type reference (declaring type incl. type arguments) + /// + public virtual IReturnType DeclaringTypeReference { + get { + return declaringTypeReference ?? this.DeclaringType.DefaultReturnType; + } + set { + declaringTypeReference = value; + } + } + + public IList InterfaceImplementations { + get { + return interfaceImplementations ?? (interfaceImplementations = new List()); + } + } + public AbstractMember(IClass declaringType, string name) : base(declaringType, name) { } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs index ae522e39ac..8adc0384bf 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs @@ -162,6 +162,9 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType) || CheckParameters(l[i].Parameters)) { l[i] = (IMethod)l[i].Clone(); + if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { + l[i].DeclaringTypeReference = this; + } l[i].ReturnType = TranslateType(l[i].ReturnType); for (int j = 0; j < l[i].Parameters.Count; ++j) { l[i].Parameters[j].ReturnType = TranslateType(l[i].Parameters[j].ReturnType); @@ -177,6 +180,9 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType) || CheckParameters(l[i].Parameters)) { l[i] = (IProperty)l[i].Clone(); + if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { + l[i].DeclaringTypeReference = this; + } l[i].ReturnType = TranslateType(l[i].ReturnType); for (int j = 0; j < l[i].Parameters.Count; ++j) { l[i].Parameters[j].ReturnType = TranslateType(l[i].Parameters[j].ReturnType); @@ -192,6 +198,9 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType)) { l[i] = (IField)l[i].Clone(); + if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { + l[i].DeclaringTypeReference = this; + } l[i].ReturnType = TranslateType(l[i].ReturnType); } } @@ -204,6 +213,9 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType)) { l[i] = (IEvent)l[i].Clone(); + if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { + l[i].DeclaringTypeReference = this; + } l[i].ReturnType = TranslateType(l[i].ReturnType); } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultEvent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultEvent.cs index 1c4e2a80f1..9bfb0ce72d 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultEvent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultEvent.cs @@ -11,7 +11,6 @@ namespace ICSharpCode.SharpDevelop.Dom { public class DefaultEvent : AbstractMember, IEvent { - DomRegion bodyRegion; IMethod addMethod; IMethod removeMethod; IMethod raiseMethod; @@ -22,18 +21,13 @@ namespace ICSharpCode.SharpDevelop.Dom } } - public virtual DomRegion BodyRegion { - get { - return bodyRegion; - } - protected set { - bodyRegion = value; - } - } - public override IMember Clone() { - return new DefaultEvent(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType); + DefaultEvent de = new DefaultEvent(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType); + foreach (ExplicitInterfaceImplementation eii in InterfaceImplementations) { + de.InterfaceImplementations.Add(eii.Clone()); + } + return de; } public DefaultEvent(IClass declaringType, string name) : base(declaringType, name) @@ -44,7 +38,7 @@ namespace ICSharpCode.SharpDevelop.Dom { this.ReturnType = type; this.Region = region; - this.bodyRegion = bodyRegion; + this.BodyRegion = bodyRegion; Modifiers = (ModifierEnum)m; if (Modifiers == ModifierEnum.None) { Modifiers = ModifierEnum.Private; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs index 967971199e..dda962fda1 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs @@ -49,8 +49,6 @@ namespace ICSharpCode.SharpDevelop.Dom [Serializable] public class DefaultMethod : AbstractMember, IMethod { - DomRegion bodyRegion; - IList parameters = null; IList typeParameters = null; @@ -72,6 +70,9 @@ namespace ICSharpCode.SharpDevelop.Dom p.typeParameters = this.typeParameters; p.documentationTag = DocumentationTag; p.isExtensionMethod = this.isExtensionMethod; + foreach (ExplicitInterfaceImplementation eii in InterfaceImplementations) { + p.InterfaceImplementations.Add(eii.Clone()); + } return p; } @@ -110,12 +111,6 @@ namespace ICSharpCode.SharpDevelop.Dom } } - public virtual DomRegion BodyRegion { - get { - return bodyRegion; - } - } - public virtual IList TypeParameters { get { if (typeParameters == null) { @@ -154,7 +149,7 @@ namespace ICSharpCode.SharpDevelop.Dom { this.ReturnType = type; this.Region = region; - this.bodyRegion = bodyRegion; + this.BodyRegion = bodyRegion; Modifiers = m; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultProperty.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultProperty.cs index e51e1813be..234b4d0a32 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultProperty.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultProperty.cs @@ -12,7 +12,6 @@ namespace ICSharpCode.SharpDevelop.Dom { public class DefaultProperty : AbstractMember, IProperty { - DomRegion bodyRegion = DomRegion.Empty; DomRegion getterRegion = DomRegion.Empty; DomRegion setterRegion = DomRegion.Empty; @@ -49,17 +48,14 @@ namespace ICSharpCode.SharpDevelop.Dom { } } - public virtual DomRegion BodyRegion { - get { - return bodyRegion; - } - } - public override IMember Clone() { DefaultProperty p = new DefaultProperty(Name, ReturnType, Modifiers, Region, BodyRegion, DeclaringType); p.parameters = DefaultParameter.Clone(this.Parameters); p.accessFlags = this.accessFlags; + foreach (ExplicitInterfaceImplementation eii in InterfaceImplementations) { + p.InterfaceImplementations.Add(eii.Clone()); + } return p; } @@ -101,7 +97,7 @@ namespace ICSharpCode.SharpDevelop.Dom { { this.ReturnType = type; this.Region = region; - this.bodyRegion = bodyRegion; + this.BodyRegion = bodyRegion; Modifiers = m; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs index f57d314e8c..4939a89dfb 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.SharpDevelop.Dom StringComparer comparer = m.DeclaringType.ProjectContent.Language.NameComparer; foreach (IMethod oldMethod in c.Methods) { if (comparer.Equals(oldMethod.Name, m.Name)) { - if (m.IsStatic == oldMethod.IsStatic) { + if (m.IsStatic == oldMethod.IsStatic && object.Equals(m.ReturnType, oldMethod.ReturnType)) { if (DiffUtility.Compare(oldMethod.Parameters, m.Parameters) == 0) { ok = false; break; @@ -118,7 +118,7 @@ namespace ICSharpCode.SharpDevelop.Dom StringComparer comparer = p.DeclaringType.ProjectContent.Language.NameComparer; foreach (IProperty oldProperty in c.Properties) { if (comparer.Equals(oldProperty.Name, p.Name)) { - if (p.IsStatic == oldProperty.IsStatic) { + if (p.IsStatic == oldProperty.IsStatic && object.Equals(p.ReturnType, oldProperty.ReturnType)) { if (DiffUtility.Compare(oldProperty.Parameters, p.Parameters) == 0) { ok = false; break; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultUsing.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultUsing.cs index ec5b67bb37..67e3cecfe0 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultUsing.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultUsing.cs @@ -92,7 +92,13 @@ namespace ICSharpCode.SharpDevelop.Dom return null; } - public IReturnType SearchType(string partialTypeName, int typeParameterCount) + /// + /// Returns a collection of possible types that could be meant when using this Import + /// to search the type. + /// Types with the incorrect type parameter count might be returned, but for each + /// same using entry or alias entry at most one (the best matching) type should be returned. + /// + public IEnumerable SearchType(string partialTypeName, int typeParameterCount) { if (HasAliases) { foreach (KeyValuePair entry in aliases) { @@ -100,14 +106,14 @@ namespace ICSharpCode.SharpDevelop.Dom if (projectContent.Language.NameComparer.Equals(partialTypeName, aliasString)) { if (entry.Value.IsDefaultReturnType && entry.Value.GetUnderlyingClass() == null) continue; // type not found, maybe entry was a namespace - return entry.Value; + yield return entry.Value; } if (partialTypeName.Length > aliasString.Length) { if (projectContent.Language.NameComparer.Equals(partialTypeName.Substring(0, aliasString.Length + 1), aliasString + ".")) { string className = entry.Value.FullyQualifiedName + partialTypeName.Remove(0, aliasString.Length); IClass c = projectContent.GetClass(className, typeParameterCount); if (c != null) { - return c.DefaultReturnType; + yield return c.DefaultReturnType; } } } @@ -117,7 +123,7 @@ namespace ICSharpCode.SharpDevelop.Dom foreach (string str in usings) { IClass c = projectContent.GetClass(str + "." + partialTypeName, typeParameterCount); if (c != null) { - return c.DefaultReturnType; + yield return c.DefaultReturnType; } } } else { @@ -135,12 +141,11 @@ namespace ICSharpCode.SharpDevelop.Dom if (c != null) { c = projectContent.GetClass(str + "." + partialTypeName, typeParameterCount); if (c != null) { - return c.DefaultReturnType; + yield return c.DefaultReturnType; } } } } - return null; } public override string ToString() diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/ExplicitInterfaceImplementation.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/ExplicitInterfaceImplementation.cs new file mode 100644 index 0000000000..bca4311e65 --- /dev/null +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/ExplicitInterfaceImplementation.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision: 1965 $ +// + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.SharpDevelop.Dom +{ + public sealed class ExplicitInterfaceImplementation : IEquatable + { + readonly IReturnType interfaceReference; + readonly string memberName; + + public ExplicitInterfaceImplementation(IReturnType interfaceReference, string memberName) + { + this.interfaceReference = interfaceReference; + this.memberName = memberName; + } + + public IReturnType InterfaceReference { + get { return interfaceReference; } + } + + public string MemberName { + get { return memberName; } + } + + public ExplicitInterfaceImplementation Clone() + { + return this; // object is immutable, no Clone() required + } + + public override int GetHashCode() + { + return interfaceReference.GetHashCode() ^ memberName.GetHashCode(); + } + + public override bool Equals(object obj) + { + return Equals(obj as ExplicitInterfaceImplementation); + } + + public bool Equals(ExplicitInterfaceImplementation other) + { + if (other == null) + return false; + else + return this.interfaceReference == other.interfaceReference && this.memberName == other.memberName; + } + } +} diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEvent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEvent.cs index 8157e70f01..bb84d22fcb 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEvent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEvent.cs @@ -11,10 +11,6 @@ namespace ICSharpCode.SharpDevelop.Dom { public interface IEvent : IMember { - DomRegion BodyRegion { - get; - } - IMethod AddMethod { get; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs index b4520f6714..e03a136afa 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs @@ -6,6 +6,7 @@ // using System; +using System.Collections.Generic; namespace ICSharpCode.SharpDevelop.Dom { @@ -15,6 +16,15 @@ namespace ICSharpCode.SharpDevelop.Dom get; } + /// + /// Gets/Sets the declaring type reference (declaring type incl. type arguments). + /// If set to null, the getter returns the default type reference to the . + /// + IReturnType DeclaringTypeReference { + get; + set; + } + /// /// Declaration region of the member (without body!) /// @@ -38,5 +48,13 @@ namespace ICSharpCode.SharpDevelop.Dom get; set; } + + DomRegion BodyRegion { + get; + } + + IList InterfaceImplementations { + get; + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMethod.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMethod.cs index 6c538890da..d93bded335 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMethod.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMethod.cs @@ -12,10 +12,6 @@ namespace ICSharpCode.SharpDevelop.Dom { public interface IMethodOrProperty : IMember { - DomRegion BodyRegion { - get; - } - IList Parameters { get; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IUsing.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IUsing.cs index 8c73aab9b6..6f1c2f84ac 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IUsing.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IUsing.cs @@ -31,7 +31,15 @@ namespace ICSharpCode.SharpDevelop.Dom get; } - IReturnType SearchType(string partialTypeName, int typeParameterCount); + /// + /// Returns a collection of possible types that could be meant when using this Import + /// to search the type. + /// Types with the incorrect type parameter count might be returned, but for each + /// same using entry or alias entry at most one (the best matching) type should be returned. + /// + /// An IEnumerable with zero or more non-null return types. + IEnumerable SearchType(string partialTypeName, int typeParameterCount); + string SearchNamespace(string partialNamespaceName); } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/LanguageProperties.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/LanguageProperties.cs index a76c7decfd..33c59cdd55 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/LanguageProperties.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/LanguageProperties.cs @@ -169,6 +169,18 @@ namespace ICSharpCode.SharpDevelop.Dom } } + /// + /// Gets if the language enforces that explicit interface implementations are uncallable except through + /// the interface itself. + /// If this property is false, code generators may assume that multiple explicit interface implementations + /// with conflicting return types are invalid unless they are renamed. + /// + public virtual bool ExplicitInterfaceImplementationIsPrivateScope { + get { + return false; + } + } + /// /// Gets if events explicitly implementing an interface require add {} remove {} regions. /// @@ -250,6 +262,12 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public override bool ExplicitInterfaceImplementationIsPrivateScope { + get { + return true; + } + } + /// /// Gets if events explicitly implementing an interface require add {} remove {} regions. /// diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs index b3c8deca4b..176aeadacb 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs @@ -811,8 +811,7 @@ namespace ICSharpCode.SharpDevelop.Dom // Combine name with usings foreach (IUsing u in request.CurrentCompilationUnit.Usings) { if (u != null) { - IReturnType r = u.SearchType(name, request.TypeParameterCount); - if (r != null) { + foreach (IReturnType r in u.SearchType(name, request.TypeParameterCount)) { if (r.TypeParameterCount == request.TypeParameterCount) { return new SearchTypeResult(r, u); } else { @@ -823,8 +822,7 @@ namespace ICSharpCode.SharpDevelop.Dom } } if (defaultImports != null) { - IReturnType r = defaultImports.SearchType(name, request.TypeParameterCount); - if (r != null) { + foreach (IReturnType r in defaultImports.SearchType(name, request.TypeParameterCount)) { if (r.TypeParameterCount == request.TypeParameterCount) { return new SearchTypeResult(r, defaultImports); } else { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs index e5f4221c29..019d1deba3 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs @@ -431,68 +431,140 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring return member.DeclaringType.FullyQualifiedName; } - public void ImplementInterface(IReturnType interf, IDocument document, bool explicitImpl, ModifierEnum implModifier, IClass targetClass) + public virtual void ImplementInterface(IReturnType interf, IDocument document, bool explicitImpl, IClass targetClass) { List nodes = new List(); - ImplementInterface(nodes, interf, explicitImpl, implModifier, targetClass); + ImplementInterface(nodes, interf, explicitImpl, targetClass); InsertCodeAtEnd(targetClass.Region, document, nodes.ToArray()); } + static bool InterfaceMemberAlreadyImplementedParametersAreIdentical(IMember a, IMember b) + { + if (a is IMethodOrProperty && b is IMethodOrProperty) { + return DiffUtility.Compare(((IMethodOrProperty)a).Parameters, + ((IMethodOrProperty)b).Parameters) == 0; + } else { + return true; + } + } + + static T CloneAndAddExplicitImpl(T member, IClass targetClass) + where T : class, IMember + { + T copy = (T)member.Clone(); + copy.DeclaringTypeReference = targetClass.DefaultReturnType; + copy.InterfaceImplementations.Add(new ExplicitInterfaceImplementation(member.DeclaringTypeReference, member.Name)); + return copy; + } + + static bool InterfaceMemberAlreadyImplemented(IEnumerable existingMembers, T interfaceMember, + out bool requireAlternativeImplementation) + where T : class, IMember + { + IReturnType interf = interfaceMember.DeclaringTypeReference; + requireAlternativeImplementation = false; + foreach (T existing in existingMembers) { + StringComparer nameComparer = existing.DeclaringType.ProjectContent.Language.NameComparer; + + // if existing has same name as interfaceMember, and for methods the parameter list must also be identical: + if (nameComparer.Equals(existing.Name, interfaceMember.Name)) { + if (InterfaceMemberAlreadyImplementedParametersAreIdentical(existing, interfaceMember)) { + // implicit implementation found + if (object.Equals(existing.ReturnType, interfaceMember.ReturnType)) { + return true; + } else { + requireAlternativeImplementation = true; + } + } + } else { + foreach (ExplicitInterfaceImplementation eii in existing.InterfaceImplementations) { + if (object.Equals(eii.InterfaceReference, interf) && nameComparer.Equals(eii.MemberName, interfaceMember.Name)) { + if (InterfaceMemberAlreadyImplementedParametersAreIdentical(existing, interfaceMember)) { + // explicit implementation found + if (object.Equals(existing.ReturnType, interfaceMember.ReturnType)) { + return true; + } else { + requireAlternativeImplementation = true; + } + } + } + } + } + } + return false; + } + + static InterfaceImplementation CreateInterfaceImplementation(IMember interfaceMember, ClassFinder context) + { + return new InterfaceImplementation(ConvertType(interfaceMember.DeclaringTypeReference, context), interfaceMember.Name); + } + /// /// Adds the methods implementing the to the list /// . /// - public virtual void ImplementInterface(IList nodes, IReturnType interf, bool explicitImpl, ModifierEnum implModifier, IClass targetClass) + public virtual void ImplementInterface(IList nodes, IReturnType interf, bool explicitImpl, IClass targetClass) { ClassFinder context = new ClassFinder(targetClass, targetClass.Region.BeginLine + 1, 0); - TypeReference interfaceReference = ConvertType(interf, context); - Modifiers modifier = ConvertModifier(implModifier, context); + Modifiers implicitImplModifier = ConvertModifier(ModifierEnum.Public, context); + Modifiers explicitImplModifier = ConvertModifier(context.Language.ExplicitInterfaceImplementationIsPrivateScope ? ModifierEnum.None : ModifierEnum.Public, context); List targetClassEvents = targetClass.DefaultReturnType.GetEvents(); + bool requireAlternativeImplementation; foreach (IEvent e in interf.GetEvents()) { - if (targetClassEvents.Find(delegate(IEvent te) { return e.Name == te.Name; }) == null) { + if (!InterfaceMemberAlreadyImplemented(targetClassEvents, e, out requireAlternativeImplementation)) { EventDeclaration ed = ConvertMember(e, context); - if (explicitImpl) { - ed.InterfaceImplementations.Add(new InterfaceImplementation(interfaceReference, ed.Name)); + if (explicitImpl || requireAlternativeImplementation) { + ed.InterfaceImplementations.Add(CreateInterfaceImplementation(e, context)); - if (context.ProjectContent.Language.RequiresAddRemoveRegionInExplicitInterfaceImplementation) { + if (context.Language.RequiresAddRemoveRegionInExplicitInterfaceImplementation) { ed.AddRegion = new EventAddRegion(null); ed.AddRegion.Block = CreateNotImplementedBlock(); ed.RemoveRegion = new EventRemoveRegion(null); ed.RemoveRegion.Block = CreateNotImplementedBlock(); } + + targetClassEvents.Add(CloneAndAddExplicitImpl(e, targetClass)); + ed.Modifier = explicitImplModifier; + } else { + targetClassEvents.Add(e); + ed.Modifier = implicitImplModifier; } - ed.Modifier = modifier; nodes.Add(ed); } } List targetClassProperties = targetClass.DefaultReturnType.GetProperties(); foreach (IProperty p in interf.GetProperties()) { - if (targetClassProperties.Find(delegate(IProperty tp) { return p.Name == tp.Name; }) == null) { + if (!InterfaceMemberAlreadyImplemented(targetClassProperties, p, out requireAlternativeImplementation)) { AttributedNode pd = ConvertMember(p, context); - if (explicitImpl) { - InterfaceImplementation impl = new InterfaceImplementation(interfaceReference, p.Name); + if (explicitImpl || requireAlternativeImplementation) { + InterfaceImplementation impl = CreateInterfaceImplementation(p, context); if (pd is IndexerDeclaration) { ((IndexerDeclaration)pd).InterfaceImplementations.Add(impl); } else { ((PropertyDeclaration)pd).InterfaceImplementations.Add(impl); } + targetClassProperties.Add(CloneAndAddExplicitImpl(p, targetClass)); + pd.Modifier = explicitImplModifier; + } else { + targetClassProperties.Add(p); + pd.Modifier = implicitImplModifier; } - pd.Modifier = modifier; nodes.Add(pd); } } List targetClassMethods = targetClass.DefaultReturnType.GetMethods(); foreach (IMethod m in interf.GetMethods()) { - if (targetClassMethods.Find(delegate(IMethod mp) { - return m.Name == mp.Name && DiffUtility.Compare(m.Parameters, mp.Parameters) == 0; - }) == null) - { + if (!InterfaceMemberAlreadyImplemented(targetClassMethods, m, out requireAlternativeImplementation)) { MethodDeclaration md = ConvertMember(m, context) as MethodDeclaration; if (md != null) { - if (explicitImpl) { - md.InterfaceImplementations.Add(new InterfaceImplementation(interfaceReference, md.Name)); + if (explicitImpl || requireAlternativeImplementation) { + md.InterfaceImplementations.Add(CreateInterfaceImplementation(m, context)); + targetClassMethods.Add(CloneAndAddExplicitImpl(m, targetClass)); + md.Modifier = explicitImplModifier; + } else { + targetClassMethods.Add(m); + md.Modifier = implicitImplModifier; } - md.Modifier = modifier; nodes.Add(md); } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs index 3b5ca23a3b..5873779b3b 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs @@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom { public const long FileMagic = 0x11635233ED2F428C; public const long IndexFileMagic = 0x11635233ED2F427D; - public const short FileVersion = 8; + public const short FileVersion = 9; ProjectContentRegistry registry; string cacheDirectory; @@ -221,10 +221,12 @@ namespace ICSharpCode.SharpDevelop.Dom { ReflectionProjectContent pc; + // for writing: readonly BinaryWriter writer; readonly Dictionary classIndices = new Dictionary(); readonly Dictionary stringDict = new Dictionary(); + // for reading: readonly BinaryReader reader; IReturnType[] types; string[] stringArray; @@ -494,16 +496,13 @@ namespace ICSharpCode.SharpDevelop.Dom } } foreach (IField f in c.Fields) { - AddStrings(stringList, f); - AddExternalType(f.ReturnType, externalTypes, classCount); + CreateExternalTypeListMember(externalTypes, stringList, classCount, f); } foreach (IEvent f in c.Events) { - AddStrings(stringList, f); - AddExternalType(f.ReturnType, externalTypes, classCount); + CreateExternalTypeListMember(externalTypes, stringList, classCount, f); } foreach (IProperty p in c.Properties) { - AddStrings(stringList, p); - AddExternalType(p.ReturnType, externalTypes, classCount); + CreateExternalTypeListMember(externalTypes, stringList, classCount, p); foreach (IParameter parameter in p.Parameters) { AddString(stringList, parameter.Name); AddStrings(stringList, parameter.Attributes); @@ -511,8 +510,7 @@ namespace ICSharpCode.SharpDevelop.Dom } } foreach (IMethod m in c.Methods) { - AddStrings(stringList, m); - AddExternalType(m.ReturnType, externalTypes, classCount); + CreateExternalTypeListMember(externalTypes, stringList, classCount, m); foreach (IParameter parameter in m.Parameters) { AddString(stringList, parameter.Name); AddStrings(stringList, parameter.Attributes); @@ -528,10 +526,17 @@ namespace ICSharpCode.SharpDevelop.Dom } } - void AddStrings(List stringList, IMember member) + void CreateExternalTypeListMember(List externalTypes, + List stringList, int classCount, + IMember member) { AddString(stringList, member.Name); AddStrings(stringList, member.Attributes); + foreach (ExplicitInterfaceImplementation eii in member.InterfaceImplementations) { + AddString(stringList, eii.MemberName); + AddExternalType(eii.InterfaceReference, externalTypes, classCount); + } + AddExternalType(member.ReturnType, externalTypes, classCount); } void AddString(List stringList, string text) @@ -657,6 +662,11 @@ namespace ICSharpCode.SharpDevelop.Dom WriteString(m.Name); writer.Write((int)m.Modifiers); WriteAttributes(m.Attributes); + writer.Write((ushort)m.InterfaceImplementations.Count); + foreach (ExplicitInterfaceImplementation iee in m.InterfaceImplementations) { + WriteType(iee.InterfaceReference); + WriteString(iee.MemberName); + } if (!(m is IMethod)) { // method must store ReturnType AFTER Template definitions WriteType(m.ReturnType); @@ -668,6 +678,10 @@ namespace ICSharpCode.SharpDevelop.Dom // name is already read by the method that calls the member constructor m.Modifiers = (ModifierEnum)reader.ReadInt32(); ReadAttributes(m); + int interfaceImplCount = reader.ReadUInt16(); + for (int i = 0; i < interfaceImplCount; i++) { + m.InterfaceImplementations.Add(new ExplicitInterfaceImplementation(ReadType(), ReadString())); + } if (!(m is IMethod)) { m.ReturnType = ReadType(); }