From 9271e6d1fbaf82d833d243158200b34a1767fdb8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 19 May 2005 13:44:01 +0000 Subject: [PATCH] Implemented "Find references". git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@149 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/ICSharpCode.SharpDevelop.csproj | 2 + .../Src/Commands/ClassMemberMenuBuilder.cs | 71 ++----- .../Src/Dom/Implementations/DefaultClass.cs | 11 +- .../Dom/Implementations/DefaultParameter.cs | 23 +-- .../Src/Dom/Implementations/LazyReturnType.cs | 2 +- .../CaseSensitiveProjectContent.cs | 52 +---- .../Services/ParserService/ParserService.cs | 20 +- .../ParseableFileContentEnumerator.cs | 127 ++++++++++++ .../RefactoringService/RefactoringService.cs | 193 ++++++++++++++++++ .../Services/RefactoringService/Reference.cs | 63 ++++++ src/Main/Base/Test/ReflectionLayerTests.cs | 12 ++ 11 files changed, 453 insertions(+), 123 deletions(-) create mode 100644 src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs create mode 100644 src/Main/Base/Project/Src/Services/RefactoringService/Reference.cs diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 01b3f8a229..b197440db2 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -665,6 +665,8 @@ + + diff --git a/src/Main/Base/Project/Src/Commands/ClassMemberMenuBuilder.cs b/src/Main/Base/Project/Src/Commands/ClassMemberMenuBuilder.cs index e90572ae2f..2af359c5ae 100644 --- a/src/Main/Base/Project/Src/Commands/ClassMemberMenuBuilder.cs +++ b/src/Main/Base/Project/Src/Commands/ClassMemberMenuBuilder.cs @@ -32,7 +32,6 @@ namespace ICSharpCode.SharpDevelop.Commands ClassMemberBookmark bookmark = (ClassMemberBookmark)owner; IMember member = bookmark.Member; List list = new List(); - cmd = new MenuCommand("&Rename", Rename); cmd.Tag = member; list.Add(cmd); @@ -55,12 +54,11 @@ namespace ICSharpCode.SharpDevelop.Commands return list.ToArray(); } - #region GoToBase void GoToBase(object sender, EventArgs e) { MenuCommand item = (MenuCommand)sender; IMember member = (IMember)item.Tag; - IMember baseMember = FindBaseMember(member); + IMember baseMember = RefactoringService.FindBaseMember(member); if (baseMember != null) { ICompilationUnit cu = baseMember.DeclaringType.CompilationUnit; if (cu != null) { @@ -77,49 +75,6 @@ namespace ICSharpCode.SharpDevelop.Commands } } - IMember FindSimilarMember(IClass type, IMember member) - { - if (member is IMethod) { - IMethod parentMethod = (IMethod)member; - foreach (IMethod m in type.Methods) { - if (string.Equals(parentMethod.Name, m.Name, StringComparison.InvariantCultureIgnoreCase)) { - if (m.IsStatic == parentMethod.IsStatic) { - if (DiffUtility.Compare(parentMethod.Parameters, m.Parameters) == 0) { - return m; - } - } - } - } - } else if (member is IProperty) { - IProperty parentMethod = (IProperty)member; - foreach (IProperty m in type.Properties) { - if (string.Equals(parentMethod.Name, m.Name, StringComparison.InvariantCultureIgnoreCase)) { - if (m.IsStatic == parentMethod.IsStatic) { - if (DiffUtility.Compare(parentMethod.Parameters, m.Parameters) == 0) { - return m; - } - } - } - } - } - return null; - } - - IMember FindBaseMember(IMember member) - { - IClass parentClass = member.DeclaringType; - IClass baseClass = parentClass.BaseClass; - if (baseClass == null) return null; - - foreach (IClass childClass in baseClass.ClassInheritanceTree) { - IMember m = FindSimilarMember(childClass, member); - if (m != null) - return m; - } - return null; - } - #endregion - void Rename(object sender, EventArgs e) { MenuCommand item = (MenuCommand)sender; @@ -136,7 +91,7 @@ namespace ICSharpCode.SharpDevelop.Commands foreach (IClass derivedClass in derivedClasses) { if (derivedClass.CompilationUnit == null) continue; if (derivedClass.CompilationUnit.FileName == null) continue; - IMember m = FindSimilarMember(derivedClass, member); + IMember m = RefactoringService.FindSimilarMember(derivedClass, member); if (m != null && m.Region != null) { SearchResult res = new SimpleSearchResult(m.FullyQualifiedName, new Point(m.Region.BeginColumn - 1, m.Region.BeginLine - 1)); res.ProvidedDocumentInformation = GetDocumentInformation(derivedClass.CompilationUnit.FileName); @@ -146,6 +101,21 @@ namespace ICSharpCode.SharpDevelop.Commands SearchReplaceInFilesManager.ShowSearchResults(results); } + void FindReferences(object sender, EventArgs e) + { + MenuCommand item = (MenuCommand)sender; + IMember member = (IMember)item.Tag; + List list = RefactoringService.FindReferences(member, null); + if (list == null) return; + List results = new List(); + foreach (Reference r in list) { + SearchResult res = new SearchResult(r.Offset, r.Length); + res.ProvidedDocumentInformation = GetDocumentInformation(r.FileName); + results.Add(res); + } + SearchReplaceInFilesManager.ShowSearchResults(results); + } + ProvidedDocumentInformation GetDocumentInformation(string fileName) { foreach (IViewContent content in WorkbenchSingleton.Workbench.ViewContentCollection) { @@ -159,12 +129,5 @@ namespace ICSharpCode.SharpDevelop.Commands ITextBufferStrategy strategy = StringTextBufferStrategy.CreateTextBufferFromFile(fileName); return new ProvidedDocumentInformation(strategy, fileName, 0); } - - void FindReferences(object sender, EventArgs e) - { - MenuCommand item = (MenuCommand)sender; - IMember member = (IMember)item.Tag; - MessageService.ShowMessage("Not implemented."); - } } } diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs index 656a9ec85a..d8ebee24fc 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs @@ -512,14 +512,13 @@ namespace ICSharpCode.SharpDevelop.Dom } else { baseType = baseTypeStruct.parent.ProjectContent.SearchType(baseTypeStruct.name, baseTypeStruct.parent, 1, 1); } - if (baseType != null) { - currentClass = baseType; - + if (baseType == null || finishedClasses.Contains(baseType)) { // prevent enumerating interfaces multiple times and endless loops when // circular inheritance is found - if (finishedClasses.Contains(currentClass)) { - return MoveNext(); - } + return MoveNext(); + } else { + currentClass = baseType; + finishedClasses.Add(currentClass); PutBaseClassesOnStack(currentClass); return true; diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs index 83c5e372f8..f5d50f8481 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs @@ -131,24 +131,23 @@ namespace ICSharpCode.SharpDevelop.Dom return r; } - public virtual int CompareTo(IParameter value) { + public virtual int CompareTo(IParameter value) + { + if (value == null) return -1; int cmp; - if (Name != null) { - cmp = Name.CompareTo(value.Name); - if (cmp != 0) { - return cmp; - } - } - - if(0 != (cmp = (int)(Modifier - value.Modifier))) + if(0 != (cmp = ((int)Modifier - (int)value.Modifier))) return cmp; - return DiffUtility.Compare(attributes, value.Attributes); + if (ReturnType.Equals(value.ReturnType)) + return 0; + else + return -1; } - int IComparable.CompareTo(object value) { - return CompareTo((IParameter)value); + int IComparable.CompareTo(object value) + { + return CompareTo(value as IParameter); } } } diff --git a/src/Main/Base/Project/Src/Dom/Implementations/LazyReturnType.cs b/src/Main/Base/Project/Src/Dom/Implementations/LazyReturnType.cs index f8116cea8d..847d7cd083 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/LazyReturnType.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/LazyReturnType.cs @@ -130,7 +130,7 @@ namespace ICSharpCode.SharpDevelop.Dom else return false; } - if (declaringClass != rt.declaringClass) return false; + if (declaringClass.FullyQualifiedName != rt.declaringClass.FullyQualifiedName) return false; return name == rt.name; } diff --git a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs index e592409efc..2c548df324 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/CaseSensitiveProjectContent.cs @@ -210,23 +210,6 @@ namespace ICSharpCode.Core new AddReferenceDelegate(AddReference).BeginInvoke(e.ReferenceProjectItem, null, null); } - delegate string GetParseableContentDelegate(string fileName); - - Encoding getParseableContentEncoding; - - string GetParseableFileContent(string fileName) - { - // Loading the source files is done asynchronously: - // While one file is parsed, the next is already loaded from disk. - string res = project.GetParseableFileContent(fileName); - if (res != null) - return res; - // load file - using (StreamReader r = new StreamReader(fileName, getParseableContentEncoding)) { - return r.ReadToEnd(); - } - } - internal int GetInitializationWorkAmount() { return project.Items.Count; @@ -235,42 +218,23 @@ namespace ICSharpCode.Core internal void Initialize2() { if (!initializing) return; - ProjectItem[] arr = project.Items.ToArray(); int progressStart = StatusBarService.ProgressMonitor.WorkDone; + ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(project); try { - Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties())); - getParseableContentEncoding = Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252)); - textEditorProperties = null; - StatusBarService.ProgressMonitor.TaskName = "Parsing " + project.Name + "..."; - GetParseableContentDelegate pcd = new GetParseableContentDelegate(GetParseableFileContent); - ProjectItem item; - ProjectItem nextItem = arr[0]; - IAsyncResult res = null; - for (int i = 0; i < arr.Length; ++i) { - item = nextItem; - nextItem = (i < arr.Length - 1) ? arr[i + 1] : null; + while (enumerator.MoveNext()) { + int i = enumerator.Index; if ((i % 5) == 2) StatusBarService.ProgressMonitor.WorkDone = progressStart + i; - if (item.ItemType == ItemType.Compile) { - string fileName = item.FileName; - string fileContent; - if (res != null) - fileContent = pcd.EndInvoke(res); - else - fileContent = GetParseableFileContent(fileName); - if (nextItem != null && nextItem.ItemType == ItemType.Compile) - res = pcd.BeginInvoke(nextItem.FileName, null, null); - else - res = null; - ParserService.ParseFile(this, fileName, fileContent, true, false); - } + + ParserService.ParseFile(this, enumerator.CurrentFileName, enumerator.CurrentFileContent, true, false); + if (!initializing) return; } } finally { initializing = false; - StatusBarService.ProgressMonitor.WorkDone = progressStart + arr.Length; - getParseableContentEncoding = null; + StatusBarService.ProgressMonitor.WorkDone = progressStart + enumerator.ItemCount; + enumerator.Dispose(); } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index ba9939ebc7..6f26e44d94 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -47,12 +47,6 @@ namespace ICSharpCode.Core } } - public static IEnumerable AllProjectContents { - get { - return projectContents.Values; - } - } - static IProjectContent forcedContent; /// /// Used for unit tests ONLY!! @@ -62,6 +56,14 @@ namespace ICSharpCode.Core forcedContent = content; } + public static IEnumerable AllProjectContents { + get { + return projectContents.Values; + } + } + + + static ParserService() { try { @@ -101,6 +103,12 @@ namespace ICSharpCode.Core loadSolutionProjectsThread.Start(); } + public static bool LoadSolutionProjectsThreadRunning { + get { + return loadSolutionProjectsThread != null; + } + } + static void LoadSolutionProjects() { try { diff --git a/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs b/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs new file mode 100644 index 0000000000..ebd797c6ff --- /dev/null +++ b/src/Main/Base/Project/Src/Services/ProjectService/ParseableFileContentEnumerator.cs @@ -0,0 +1,127 @@ +/* + * Created by SharpDevelop. + * User: Daniel Grunwald + * Date: 18.05.2005 + * Time: 19:08 + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Project +{ + /// + /// Description of ParseableFileContentEnumerator. + /// + public class ParseableFileContentEnumerator : IEnumerator> + { + void IEnumerator.Reset() { + throw new NotSupportedException(); + } + + KeyValuePair current; + + object IEnumerator.Current { + get { + return current; + } + } + + public KeyValuePair Current { + get { + return current; + } + } + + public string CurrentFileName { + get { + return current.Key; + } + } + + public string CurrentFileContent { + get { + return current.Value; + } + } + + public void Dispose() + { + } + + ProjectItem[] projectItems; + + public ParseableFileContentEnumerator(IProject project) : this(project.Items.ToArray()) { } + + public ParseableFileContentEnumerator(ProjectItem[] projectItems) + { + this.projectItems = projectItems; + Properties textEditorProperties = ((Properties)PropertyService.Get("ICSharpCode.TextEditor.Document.Document.DefaultDocumentAggregatorProperties", new Properties())); + getParseableContentEncoding = Encoding.GetEncoding(textEditorProperties.Get("Encoding", 1252)); + pcd = new GetParseableContentDelegate(GetParseableFileContent); + if (projectItems.Length > 0) { + nextItem = projectItems[0]; + } + } + + delegate string GetParseableContentDelegate(IProject project, string fileName); + + GetParseableContentDelegate pcd; + + Encoding getParseableContentEncoding; + + string GetParseableFileContent(IProject project, string fileName) + { + // Loading the source files is done asynchronously: + // While one file is parsed, the next is already loaded from disk. + string res = project.GetParseableFileContent(fileName); + if (res != null) + return res; + // load file + using (StreamReader r = new StreamReader(fileName, getParseableContentEncoding)) { + return r.ReadToEnd(); + } + } + + ProjectItem nextItem; + IAsyncResult res; + int index = 0; + + public int ItemCount { + get { + return projectItems.Length; + } + } + + public int Index { + get { + return index; + } + } + + public bool MoveNext() + { + ProjectItem item = nextItem; + nextItem = (++index < projectItems.Length) ? projectItems[index] : null; + if (item == null) return false; + if (item.ItemType != ItemType.Compile) + return MoveNext(); + string fileName = item.FileName; + string fileContent; + if (res != null) + fileContent = pcd.EndInvoke(res); + else + fileContent = GetParseableFileContent(item.Project, fileName); + if (nextItem != null && nextItem.ItemType == ItemType.Compile) + res = pcd.BeginInvoke(nextItem.Project, nextItem.FileName, null, null); + else + res = null; + current = new KeyValuePair(fileName, fileContent); + return true; + } + } +} diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs index 677f65c954..43dd8e03d9 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs @@ -7,7 +7,11 @@ using System; using System.Collections.Generic; +using System.Drawing; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.Core { @@ -42,5 +46,194 @@ namespace ICSharpCode.Core return list; } #endregion + + #region FindReferences + /// + /// Find all references to the specified member. + /// + public static List FindReferences(IMember member, IProgressMonitor progressMonitor) + { + if (ParserService.LoadSolutionProjectsThreadRunning) { + MessageService.ShowMessage("Find references cannot be executed until all files have been parsed."); + return null; + } + IClass ownerClass = member.DeclaringType; + List files = GetPossibleFiles(ownerClass, member); + ParseableFileContentEnumerator enumerator = new ParseableFileContentEnumerator(files.ToArray()); + List references = new List(); + try { + if (progressMonitor != null) { + progressMonitor.BeginTask("Finding references...", files.Count); + } + while (enumerator.MoveNext()) { + if (progressMonitor != null) { + progressMonitor.WorkDone = enumerator.Index; + } + + AddReferences(references, ownerClass, member, enumerator.CurrentFileName, enumerator.CurrentFileContent); + } + } finally { + if (progressMonitor != null) { + progressMonitor.Done(); + } + enumerator.Dispose(); + } + return references; + } + + static void AddReferences(List list, IClass parentClass, IMember member, string fileName, string fileContent) + { + string lowerFileContent = fileContent.ToLower(); + if (lowerFileContent.IndexOf(parentClass.Name.ToLower()) < 0) return; + string lowerMemberName; + if (member is IMethod && ((IMethod)member).IsConstructor) + lowerMemberName = parentClass.Name.ToLower(); + else + lowerMemberName = member.Name.ToLower(); + //Console.WriteLine(fileName + " / " + lowerMemberName); + int pos = -1; + IExpressionFinder expressionFinder = null; + while ((pos = lowerFileContent.IndexOf(lowerMemberName, pos + 1)) >= 0) { + if (expressionFinder == null) { + expressionFinder = ParserService.GetExpressionFinder(fileName); + } + string expr = expressionFinder.FindFullExpression(fileContent, pos + 1); + if (expr != null) { + Point position = GetPosition(fileContent, pos); + ResolveResult rr = ParserService.Resolve(expr, position.Y, position.X, fileName, fileContent); + if (IsReferenceToMember(member, rr)) { + list.Add(new Reference(fileName, pos, lowerMemberName.Length, expr, rr)); + } + } + } + } + + static Point GetPosition(string fileContent, int pos) + { + int line = 1; + int column = 0; + for (int i = 0; i < pos; ++i) { + if (fileContent[i] == '\n') { + ++line; + column = 0; + } else { + ++column; + } + } + return new Point(column, line); + } + + static List GetPossibleFiles(IClass ownerClass, IMember member) + { + // TODO: Optimize when member is not public + List resultList = new List(); + foreach (IProject p in ProjectService.OpenSolution.Projects) { + IProjectContent pc = ParserService.GetProjectContent(p); + if (pc == null) continue; + if (pc != ownerClass.ProjectContent && !pc.HasReferenceTo(ownerClass.ProjectContent)) { + // unreferences project contents cannot reference the class + continue; + } + foreach (ProjectItem item in p.Items) { + if (item.ItemType == ItemType.Compile) { + resultList.Add(item); + } + } + } + return resultList; + } + #endregion + + public static bool IsReferenceToMember(IMember member, ResolveResult rr) + { + MemberResolveResult mrr = rr as MemberResolveResult; + if (mrr != null) + return IsSimilarMember(mrr.ResolvedMember, member); + else + return false; + } + + /// + /// Gets if member1 is the same as member2 or if member1 overrides member2. + /// + public static bool IsSimilarMember(IMember member1, IMember member2) + { + do { + if (IsSimilarMemberInternal(member1, member2)) + return true; + } while ((member1 = FindBaseMember(member1)) != null); + return false; + } + + static bool IsSimilarMemberInternal(IMember member1, IMember member2) + { + if (member1 == member2) + return true; + if (member1 == null || member2 == null) + return false; + if (member1.FullyQualifiedName != member2.FullyQualifiedName) + return false; + if (member1.IsStatic != member2.IsStatic) + return false; + if (member1 is IMethod) { + if (member2 is IMethod) { + if (DiffUtility.Compare(((IMethod)member1).Parameters, ((IMethod)member2).Parameters) != 0) + return false; + } else { + return false; + } + } + if (member1 is IProperty) { + if (member2 is IProperty) { + if (DiffUtility.Compare(((IProperty)member1).Parameters, ((IProperty)member2).Parameters) != 0) + return false; + } else { + return false; + } + } + return true; + } + + public static IMember FindSimilarMember(IClass type, IMember member) + { + if (member is IMethod) { + IMethod parentMethod = (IMethod)member; + foreach (IMethod m in type.Methods) { + if (string.Equals(parentMethod.Name, m.Name, StringComparison.InvariantCultureIgnoreCase)) { + if (m.IsStatic == parentMethod.IsStatic) { + if (DiffUtility.Compare(parentMethod.Parameters, m.Parameters) == 0) { + return m; + } + } + } + } + } else if (member is IProperty) { + IProperty parentMethod = (IProperty)member; + foreach (IProperty m in type.Properties) { + if (string.Equals(parentMethod.Name, m.Name, StringComparison.InvariantCultureIgnoreCase)) { + if (m.IsStatic == parentMethod.IsStatic) { + if (DiffUtility.Compare(parentMethod.Parameters, m.Parameters) == 0) { + return m; + } + } + } + } + } + return null; + } + + public static IMember FindBaseMember(IMember member) + { + IClass parentClass = member.DeclaringType; + IClass baseClass = parentClass.BaseClass; + if (baseClass == null) return null; + + foreach (IClass childClass in baseClass.ClassInheritanceTree) { + IMember m = FindSimilarMember(childClass, member); + if (m != null) + return m; + } + return null; + } } } diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/Reference.cs b/src/Main/Base/Project/Src/Services/RefactoringService/Reference.cs new file mode 100644 index 0000000000..145ab81532 --- /dev/null +++ b/src/Main/Base/Project/Src/Services/RefactoringService/Reference.cs @@ -0,0 +1,63 @@ +// +// +// +// +// +// + +using System; +using System.Collections.Generic; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.Core +{ + /// + /// A reference to a class or class member. + /// + public class Reference + { + string fileName; + int offset, length; + string expression; + ResolveResult resolveResult; + + public Reference(string fileName, int offset, int length, string expression, ResolveResult resolveResult) + { + this.fileName = fileName; + this.offset = offset; + this.length = length; + this.expression = expression; + this.resolveResult = resolveResult; + } + + public string FileName { + get { + return fileName; + } + } + + public int Offset { + get { + return offset; + } + } + + public int Length { + get { + return length; + } + } + + public string Expression { + get { + return expression; + } + } + + public ResolveResult ResolveResult { + get { + return resolveResult; + } + } + } +} diff --git a/src/Main/Base/Test/ReflectionLayerTests.cs b/src/Main/Base/Test/ReflectionLayerTests.cs index f46f68a3d7..4a1528fdd9 100644 --- a/src/Main/Base/Test/ReflectionLayerTests.cs +++ b/src/Main/Base/Test/ReflectionLayerTests.cs @@ -42,5 +42,17 @@ namespace ICSharpCode.SharpDevelop.Tests Assert.AreEqual("System.Runtime.InteropServices._Exception", subClasses[3].FullyQualifiedName); Assert.AreEqual("System.Object", subClasses[4].FullyQualifiedName); } + + [Test] + public void ParameterComparisonTest() + { + DefaultParameter p1 = new DefaultParameter("a", pc.GetClass("System.String").DefaultReturnType, null); + DefaultParameter p2 = new DefaultParameter("b", new GetClassReturnType(pc, "System.String"), null); + List a1 = new List(); + List a2 = new List(); + a1.Add(p1); + a2.Add(p2); + Assert.AreEqual(0, DiffUtility.Compare(a1, a2)); + } } }