From 76d9a6daa5c5663e7b5402f1e8d7a844f8bf37b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 13 Jun 2013 13:51:49 +0200 Subject: [PATCH 01/12] IKVM loader should now be a cecil loader replacement. --- .../TypeSystem/IkvmLoader.cs | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/ICSharpCode.NRefactory/TypeSystem/IkvmLoader.cs b/ICSharpCode.NRefactory/TypeSystem/IkvmLoader.cs index 73a0a6e070..60b40d693f 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IkvmLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IkvmLoader.cs @@ -112,8 +112,8 @@ namespace ICSharpCode.NRefactory.TypeSystem { if (fileName == null) throw new ArgumentNullException("fileName"); - - using (var universe = new Universe (UniverseOptions.DisablePseudoCustomAttributeRetrieval)) { + + using (var universe = new Universe (UniverseOptions.DisablePseudoCustomAttributeRetrieval | UniverseOptions.SupressReferenceTypeIdentityConversion)) { universe.AssemblyResolve += delegate(object sender, IKVM.Reflection.ResolveEventArgs args) { return universe.CreateMissingAssembly(args.Name); }; @@ -254,7 +254,6 @@ namespace ICSharpCode.NRefactory.TypeSystem if (type == null) { return SpecialType.UnknownType; } - if (type.IsByRef) { typeIndex++; return interningProvider.Intern ( @@ -1491,7 +1490,7 @@ namespace ICSharpCode.NRefactory.TypeSystem { // set base classes if (typeDefinition.IsEnum) { - foreach (var enumField in typeDefinition.GetFields (bindingFlags)) { + foreach (var enumField in typeDefinition.__GetDeclaredFields ()) { if (!enumField.IsStatic) { baseTypes.Add(ReadTypeReference(enumField.FieldType)); break; @@ -1501,7 +1500,7 @@ namespace ICSharpCode.NRefactory.TypeSystem if (typeDefinition.BaseType != null) { baseTypes.Add(ReadTypeReference(typeDefinition.BaseType)); } - foreach (var iface in typeDefinition.GetInterfaces ()) { + foreach (var iface in typeDefinition.__GetDeclaredInterfaces ()) { baseTypes.Add(ReadTypeReference(iface)); } } @@ -1509,7 +1508,7 @@ namespace ICSharpCode.NRefactory.TypeSystem void InitNestedTypes(IKVM.Reflection.Type typeDefinition, IUnresolvedTypeDefinition declaringTypeDefinition, ICollection nestedTypes) { - foreach (var nestedTypeDef in typeDefinition.GetNestedTypes (bindingFlags)) { + foreach (var nestedTypeDef in typeDefinition.__GetDeclaredTypes()) { if (IncludeInternalMembers || nestedTypeDef.IsNestedPublic || nestedTypeDef.IsNestedFamily @@ -1595,11 +1594,16 @@ namespace ICSharpCode.NRefactory.TypeSystem return false; } - static readonly BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; - void InitMembers(IKVM.Reflection.Type typeDefinition, IUnresolvedTypeDefinition td, IList members) { - foreach (var method in typeDefinition.GetMethods (bindingFlags)) { + foreach (var method in typeDefinition.__GetDeclaredMethods ()) { + if (method.IsConstructor) { + if (IsVisible(method.Attributes)) { + SymbolKind type = SymbolKind.Constructor; + members.Add(ReadConstructor(method, td, type)); + } + continue; + } if (IsVisible(method.Attributes) && !IsAccessor(method)) { SymbolKind type = SymbolKind.Method; if (method.IsSpecialName) { @@ -1610,15 +1614,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - foreach (var method in typeDefinition.GetConstructors (bindingFlags)) { - if (IsVisible(method.Attributes)) { - SymbolKind type = SymbolKind.Constructor; - members.Add(ReadConstructor(method, td, type)); - } - } - - - foreach (var field in typeDefinition.GetFields (bindingFlags)) { + foreach (var field in typeDefinition.__GetDeclaredFields ()) { if (IsVisible(field.Attributes) && !field.IsSpecialName) { members.Add(ReadField(field, td)); } @@ -1631,7 +1627,7 @@ namespace ICSharpCode.NRefactory.TypeSystem defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string; } - foreach (var property in typeDefinition.GetProperties (bindingFlags)) { + foreach (var property in typeDefinition.__GetDeclaredProperties ()) { bool getterVisible = property.GetMethod != null && IsVisible(property.GetMethod.Attributes); bool setterVisible = property.SetMethod != null && IsVisible(property.SetMethod.Attributes); if (getterVisible || setterVisible) { @@ -1653,14 +1649,14 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - foreach (var ev in typeDefinition.GetEvents (bindingFlags)) { + foreach (var ev in typeDefinition.__GetDeclaredEvents ()) { if (ev.AddMethod != null && IsVisible(ev.AddMethod.Attributes)) { members.Add(ReadEvent(ev, td)); } } } - static bool IsAccessor(MethodInfo methodInfo) + static bool IsAccessor(MethodBase methodInfo) { if (!methodInfo.IsSpecialName) return false; @@ -1677,9 +1673,9 @@ namespace ICSharpCode.NRefactory.TypeSystem #region Read Method [CLSCompliant(false)] - public IUnresolvedMethod ReadMethod(MethodInfo method, IUnresolvedTypeDefinition parentType, SymbolKind methodType = SymbolKind.Method) + public IUnresolvedMethod ReadMethod(MethodBase method, IUnresolvedTypeDefinition parentType, SymbolKind methodType = SymbolKind.Method) { - return ReadMethod(method, parentType, methodType, null); + return ReadMethod((MethodInfo)method, parentType, methodType, null); } IUnresolvedMethod ReadMethod(MethodInfo method, IUnresolvedTypeDefinition parentType, SymbolKind methodType, IUnresolvedMember accessorOwner) @@ -1689,7 +1685,7 @@ namespace ICSharpCode.NRefactory.TypeSystem var m = new DefaultUnresolvedMethod(parentType, method.Name); m.SymbolKind = methodType; m.AccessorOwner = accessorOwner; - m.HasBody = method.GetMethodBody () != null; + m.HasBody = !method.DeclaringType.IsInterface && (method.GetMethodImplementationFlags () & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.IL; var genericArguments = method.GetGenericArguments (); if (genericArguments != null) { for (int i = 0; i < genericArguments.Length; i++) { @@ -1803,9 +1799,9 @@ namespace ICSharpCode.NRefactory.TypeSystem #region Read Constructor [CLSCompliant(false)] - public IUnresolvedMethod ReadConstructor(ConstructorInfo method, IUnresolvedTypeDefinition parentType, SymbolKind methodType = SymbolKind.Method) + public IUnresolvedMethod ReadConstructor(MethodBase method, IUnresolvedTypeDefinition parentType, SymbolKind methodType = SymbolKind.Method) { - return ReadConstructor(method, parentType, methodType, null); + return ReadConstructor((ConstructorInfo)method, parentType, methodType, null); } IUnresolvedMethod ReadConstructor(ConstructorInfo method, IUnresolvedTypeDefinition parentType, SymbolKind methodType, IUnresolvedMember accessorOwner) @@ -1815,7 +1811,7 @@ namespace ICSharpCode.NRefactory.TypeSystem var m = new DefaultUnresolvedMethod(parentType, method.Name); m.SymbolKind = methodType; m.AccessorOwner = accessorOwner; - m.HasBody = method.GetMethodBody () != null; + m.HasBody = !method.DeclaringType.IsInterface && (method.GetMethodImplementationFlags () & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.IL; var genericArguments = method.GetGenericArguments (); if (genericArguments != null) { for (int i = 0; i < genericArguments.Length; i++) { @@ -1938,7 +1934,6 @@ namespace ICSharpCode.NRefactory.TypeSystem f.Accessibility = GetAccessibility(field.Attributes); f.IsReadOnly = field.IsInitOnly; f.IsStatic = field.IsStatic; - f.ReturnType = ReadTypeReference(field.FieldType, typeAttributes: field.CustomAttributes); if (field.Attributes.HasFlag (FieldAttributes.HasDefault)) { From 1e628e6b6aff6dc993317bc0eb877c503df361d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 13 Jun 2013 13:55:42 +0200 Subject: [PATCH 02/12] Took out failing tests on mono. --- .../CSharp/CodeDomConvertVisitorTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs index 4ca8b9c030..abef00c7bd 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeDomConvertVisitorTests.cs @@ -30,6 +30,7 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp { + #if !__MonoCS__ [TestFixture] public class CodeDomConvertVisitorTests : ResolverTestBase { @@ -481,4 +482,5 @@ namespace ICSharpCode.NRefactory.CSharp } #endregion } +#endif } From 742f67753d63bd372ece35dc8d36c48799d3cdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 13 Jun 2013 16:10:20 +0200 Subject: [PATCH 03/12] ResultOfAsyncCallShouldNotBeIgnoredIssue no longer underlines a large portion of the text. --- .../ResultOfAsyncCallShouldNotBeIgnoredIssue.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs index 68dd1676ec..8cdc781b24 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs @@ -42,6 +42,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring : base(ctx) { } + + AstNode GetNodeToUnderline(Expression target) + { + if (target is IdentifierExpression) + return target; + if (target is MemberReferenceExpression) + return ((MemberReferenceExpression)target).MemberNameToken; + return target; + } public override void VisitExpressionStatement(ExpressionStatement expressionStatement) { @@ -51,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return; var rr = ctx.Resolve(invocation) as InvocationResolveResult; if (rr != null && (rr.Type.IsKnownType(KnownTypeCode.Task) || rr.Type.IsKnownType(KnownTypeCode.TaskOfT))) { - AddIssue(invocation, ctx.TranslateString("Exceptions in async call will be silently ignored because the returned task is unused")); + AddIssue(GetNodeToUnderline (invocation.Target), ctx.TranslateString("Exceptions in async call will be silently ignored because the returned task is unused")); } } } From ccc2fddc6c0476747fb1d60ed14fdb3a844b6c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 13 Jun 2013 16:32:57 +0200 Subject: [PATCH 04/12] Added obsolete EmptyExpression. (Removing was a breaking change) --- .../Ast/Expressions/ErrorExpression.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs b/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs index 88753b8fac..163204448d 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ErrorExpression.cs @@ -27,6 +27,42 @@ using System; namespace ICSharpCode.NRefactory.CSharp { + [Obsolete("This class is obsolete. Remove all referencing code.")] + public class EmptyExpression : AstNode + { + #region implemented abstract members of AstNode + + public override void AcceptVisitor(IAstVisitor visitor) + { + throw new NotImplementedException(); + } + + public override T AcceptVisitor(IAstVisitor visitor) + { + throw new NotImplementedException(); + } + + public override S AcceptVisitor(IAstVisitor visitor, T data) + { + throw new NotImplementedException(); + } + + protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.PatternMatching.Match match) + { + throw new NotImplementedException(); + } + + public override NodeType NodeType { + get { + throw new NotImplementedException(); + } + } + + #endregion + + + } + public class ErrorExpression : Expression { TextLocation location; From 149dea7412a9df7cd1f128ce09a7668a15eafb5d Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 13 Jun 2013 15:47:07 +0200 Subject: [PATCH 05/12] Add TypeGraphNode to NRefactory; and move AbiComparer from NR.CSharp.Analysis to NR.Analysis --- .../ICSharpCode.NRefactory.CSharp.csproj | 1 - .../Resolver/FindReferences.cs | 2 + .../{CSharp => }/Analysis/AbiComparerTests.cs | 7 +- .../ICSharpCode.NRefactory.Tests.csproj | 6 +- .../Analysis/AbiComparer.cs | 2 +- .../Analysis/TypeGraphNode.cs | 85 +++++++++++++++++++ .../ICSharpCode.NRefactory.csproj | 4 + .../TypeSystem/AssemblyQualifiedTypeName.cs | 79 +++++++++++++++++ 8 files changed, 177 insertions(+), 9 deletions(-) rename ICSharpCode.NRefactory.Tests/{CSharp => }/Analysis/AbiComparerTests.cs (95%) rename {ICSharpCode.NRefactory.CSharp => ICSharpCode.NRefactory}/Analysis/AbiComparer.cs (99%) create mode 100644 ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs create mode 100644 ICSharpCode.NRefactory/TypeSystem/AssemblyQualifiedTypeName.cs diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 1cd11064d9..b45200bd78 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -516,7 +516,6 @@ - diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs index 54f48bb38b..608d992861 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs @@ -72,6 +72,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// public bool WholeVirtualSlot { get; set; } + //public bool FindAllOverloads { get; set; } + /// /// Specifies whether to look for references in documentation comments. /// This will find entity references in cref attributes and diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Analysis/AbiComparerTests.cs b/ICSharpCode.NRefactory.Tests/Analysis/AbiComparerTests.cs similarity index 95% rename from ICSharpCode.NRefactory.Tests/CSharp/Analysis/AbiComparerTests.cs rename to ICSharpCode.NRefactory.Tests/Analysis/AbiComparerTests.cs index b6ee5388fc..057babe0c3 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Analysis/AbiComparerTests.cs +++ b/ICSharpCode.NRefactory.Tests/Analysis/AbiComparerTests.cs @@ -25,16 +25,13 @@ // THE SOFTWARE. using System; -using System.IO; using System.Linq; -using System.Threading; -using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; using NUnit.Framework; using ICSharpCode.NRefactory.CSharp.CodeCompletion; -namespace ICSharpCode.NRefactory.CSharp.Analysis +namespace ICSharpCode.NRefactory.Analysis { [TestFixture] public class AbiComparerTests diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 5a228d2f89..1b40722578 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -93,6 +93,7 @@ Properties\GlobalAssemblyInfo.cs + @@ -396,7 +397,6 @@ - @@ -439,7 +439,9 @@ False - + + + diff --git a/ICSharpCode.NRefactory.CSharp/Analysis/AbiComparer.cs b/ICSharpCode.NRefactory/Analysis/AbiComparer.cs similarity index 99% rename from ICSharpCode.NRefactory.CSharp/Analysis/AbiComparer.cs rename to ICSharpCode.NRefactory/Analysis/AbiComparer.cs index f00d9a081d..567f12a52f 100644 --- a/ICSharpCode.NRefactory.CSharp/Analysis/AbiComparer.cs +++ b/ICSharpCode.NRefactory/Analysis/AbiComparer.cs @@ -28,7 +28,7 @@ using ICSharpCode.NRefactory.TypeSystem; using System.Collections.Generic; using System.Linq; -namespace ICSharpCode.NRefactory.CSharp +namespace ICSharpCode.NRefactory.Analysis { /// /// Used to check the compatibility state of two compilations. diff --git a/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs b/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs new file mode 100644 index 0000000000..ed2384dbd8 --- /dev/null +++ b/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs @@ -0,0 +1,85 @@ +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Analysis +{ + public sealed class TypeGraphNode + { + readonly ITypeDefinition typeDef; + readonly List baseTypes = new List(); + readonly List derivedTypes = new List(); + + /// + /// Creates a new unconnected type graph node. + /// + public TypeGraphNode(ITypeDefinition typeDef) + { + this.typeDef = typeDef; + } + + public ITypeDefinition TypeDefinition { + get { return typeDef; } + } + + public IList DerivedTypes { + get { return derivedTypes; } + } + + public IList BaseTypes { + get { return baseTypes; } + } + + /// + /// Builds a graph of all type definitions in the specified set of project contents. + /// + /// The resulting graph may be cyclic if there are cyclic type definitions. + public static Dictionary BuildTypeInheritanceGraph(IEnumerable compilations) + { + if (compilations == null) + throw new ArgumentNullException("compilations"); + Dictionary dict = new Dictionary(); + foreach (ICompilation compilation in compilations) { + foreach (ITypeDefinition typeDef in compilation.MainAssembly.GetAllTypeDefinitions()) { + // Overwrite previous entry - duplicates can occur if there are multiple versions of the + // same project loaded in the solution (e.g. separate .csprojs for separate target frameworks) + dict[new AssemblyQualifiedTypeName(typeDef)] = new TypeGraphNode(typeDef); + } + } + foreach (ICompilation compilation in compilations) { + foreach (ITypeDefinition typeDef in compilation.MainAssembly.GetAllTypeDefinitions()) { + TypeGraphNode typeNode = dict[new AssemblyQualifiedTypeName(typeDef)]; + foreach (IType baseType in typeDef.DirectBaseTypes) { + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef != null) { + TypeGraphNode baseTypeNode; + if (dict.TryGetValue(new AssemblyQualifiedTypeName(baseTypeDef), out baseTypeNode)) { + typeNode.BaseTypes.Add(baseTypeNode); + baseTypeNode.DerivedTypes.Add(typeNode); + } + } + } + } + } + return dict; + } + } +} diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index aab5480a98..d3979ad520 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -82,6 +82,8 @@ + + @@ -137,6 +139,7 @@ + @@ -277,6 +280,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/AssemblyQualifiedTypeName.cs b/ICSharpCode.NRefactory/TypeSystem/AssemblyQualifiedTypeName.cs new file mode 100644 index 0000000000..8b07c5197c --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/AssemblyQualifiedTypeName.cs @@ -0,0 +1,79 @@ +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; + +namespace ICSharpCode.NRefactory.TypeSystem +{ + public struct AssemblyQualifiedTypeName : IEquatable + { + public readonly string AssemblyName; + public readonly FullTypeName TypeName; + + public AssemblyQualifiedTypeName(FullTypeName typeName, string assemblyName) + { + this.AssemblyName = assemblyName; + this.TypeName = typeName; + } + + public AssemblyQualifiedTypeName(ITypeDefinition typeDefinition) + { + this.AssemblyName = typeDefinition.ParentAssembly.AssemblyName; + this.TypeName = typeDefinition.FullTypeName; + } + + public override string ToString() + { + if (string.IsNullOrEmpty(AssemblyName)) + return TypeName.ToString(); + else + return TypeName.ToString() + ", " + AssemblyName; + } + + public override bool Equals(object obj) + { + return (obj is AssemblyQualifiedTypeName) && Equals((AssemblyQualifiedTypeName)obj); + } + + public bool Equals(AssemblyQualifiedTypeName other) + { + return this.AssemblyName == other.AssemblyName && this.TypeName == other.TypeName; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked { + if (AssemblyName != null) + hashCode += 1000000007 * AssemblyName.GetHashCode(); + hashCode += TypeName.GetHashCode(); + } + return hashCode; + } + + public static bool operator ==(AssemblyQualifiedTypeName lhs, AssemblyQualifiedTypeName rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(AssemblyQualifiedTypeName lhs, AssemblyQualifiedTypeName rhs) + { + return !lhs.Equals(rhs); + } + } +} From 47df99654054f550cdf86fc8ae0b13cce7d2b472 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 13 Jun 2013 16:38:35 +0200 Subject: [PATCH 06/12] Add TypeGraph --- .../Analysis/MemberCollector.cs | 32 ++++++++ ICSharpCode.NRefactory/Analysis/TypeGraph.cs | 82 +++++++++++++++++++ .../Analysis/TypeGraphNode.cs | 34 -------- .../ICSharpCode.NRefactory.csproj | 2 + 4 files changed, 116 insertions(+), 34 deletions(-) create mode 100644 ICSharpCode.NRefactory/Analysis/MemberCollector.cs create mode 100644 ICSharpCode.NRefactory/Analysis/TypeGraph.cs diff --git a/ICSharpCode.NRefactory/Analysis/MemberCollector.cs b/ICSharpCode.NRefactory/Analysis/MemberCollector.cs new file mode 100644 index 0000000000..d0fcc40bbe --- /dev/null +++ b/ICSharpCode.NRefactory/Analysis/MemberCollector.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Analysis +{ + public class MemberCollector + { + public static IEnumerable GetRelatedMembers(TypeGraph g, IMember m, bool includeOverloads) + { + throw new NotImplementedException(); + } + } +} diff --git a/ICSharpCode.NRefactory/Analysis/TypeGraph.cs b/ICSharpCode.NRefactory/Analysis/TypeGraph.cs new file mode 100644 index 0000000000..12e8abf261 --- /dev/null +++ b/ICSharpCode.NRefactory/Analysis/TypeGraph.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Analysis +{ + /// + /// A graph where type definitions are nodes; and edges are given by inheritance. + /// + public class TypeGraph + { + Dictionary dict; + + /// + /// Builds a graph of all type definitions in the specified set of assemblies. + /// + /// The input assemblies. The assemblies may belong to multiple compilations. + /// The resulting graph may be cyclic if there are cyclic type definitions. + public TypeGraph(IEnumerable assemblies) + { + if (assemblies == null) + throw new ArgumentNullException("assemblies"); + dict = new Dictionary(); + foreach (IAssembly assembly in assemblies) { + foreach (ITypeDefinition typeDef in assembly.GetAllTypeDefinitions()) { + // Overwrite previous entry - duplicates can occur if there are multiple versions of the + // same project loaded in the solution (e.g. separate .csprojs for separate target frameworks) + dict[new AssemblyQualifiedTypeName(typeDef)] = new TypeGraphNode(typeDef); + } + } + foreach (IAssembly assembly in assemblies) { + foreach (ITypeDefinition typeDef in assembly.GetAllTypeDefinitions()) { + TypeGraphNode typeNode = dict[new AssemblyQualifiedTypeName(typeDef)]; + foreach (IType baseType in typeDef.DirectBaseTypes) { + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef != null) { + TypeGraphNode baseTypeNode; + if (dict.TryGetValue(new AssemblyQualifiedTypeName(baseTypeDef), out baseTypeNode)) { + typeNode.BaseTypes.Add(baseTypeNode); + baseTypeNode.DerivedTypes.Add(typeNode); + } + } + } + } + } + } + + public TypeGraphNode GetNode(ITypeDefinition typeDefinition) + { + if (typeDefinition == null) + return null; + return GetNode(new AssemblyQualifiedTypeName(typeDefinition)); + } + + public TypeGraphNode GetNode(AssemblyQualifiedTypeName typeName) + { + TypeGraphNode node; + if (dict.TryGetValue(typeName, out node)) + return node; + else + return null; + } + } +} diff --git a/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs b/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs index ed2384dbd8..7b562d553b 100644 --- a/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs +++ b/ICSharpCode.NRefactory/Analysis/TypeGraphNode.cs @@ -47,39 +47,5 @@ namespace ICSharpCode.NRefactory.Analysis public IList BaseTypes { get { return baseTypes; } } - - /// - /// Builds a graph of all type definitions in the specified set of project contents. - /// - /// The resulting graph may be cyclic if there are cyclic type definitions. - public static Dictionary BuildTypeInheritanceGraph(IEnumerable compilations) - { - if (compilations == null) - throw new ArgumentNullException("compilations"); - Dictionary dict = new Dictionary(); - foreach (ICompilation compilation in compilations) { - foreach (ITypeDefinition typeDef in compilation.MainAssembly.GetAllTypeDefinitions()) { - // Overwrite previous entry - duplicates can occur if there are multiple versions of the - // same project loaded in the solution (e.g. separate .csprojs for separate target frameworks) - dict[new AssemblyQualifiedTypeName(typeDef)] = new TypeGraphNode(typeDef); - } - } - foreach (ICompilation compilation in compilations) { - foreach (ITypeDefinition typeDef in compilation.MainAssembly.GetAllTypeDefinitions()) { - TypeGraphNode typeNode = dict[new AssemblyQualifiedTypeName(typeDef)]; - foreach (IType baseType in typeDef.DirectBaseTypes) { - ITypeDefinition baseTypeDef = baseType.GetDefinition(); - if (baseTypeDef != null) { - TypeGraphNode baseTypeNode; - if (dict.TryGetValue(new AssemblyQualifiedTypeName(baseTypeDef), out baseTypeNode)) { - typeNode.BaseTypes.Add(baseTypeNode); - baseTypeNode.DerivedTypes.Add(typeNode); - } - } - } - } - } - return dict; - } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index d3979ad520..00041d86d7 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -83,6 +83,8 @@ + + From 76d4845bbe594bb8d6727c69492c382362fde449 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 13 Jun 2013 18:05:02 +0200 Subject: [PATCH 07/12] Add rename API (not implemented yet). --- .../ICSharpCode.NRefactory.CSharp.csproj | 1 + .../Resolver/FindReferences.cs | 102 +++++++++++++++--- .../Resolver/RenameCallbackArguments.cs | 31 ++++++ 3 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 ICSharpCode.NRefactory.CSharp/Resolver/RenameCallbackArguments.cs diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index b45200bd78..aa3954d20b 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -363,6 +363,7 @@ + diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs index 608d992861..495d2f91e6 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.Semantics; @@ -220,16 +221,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region GetSearchScopes - public IList GetSearchScopes(IEntity entity) + public IList GetSearchScopes(ISymbol symbol) { + if (symbol == null) + throw new ArgumentNullException("symbol"); + switch (symbol.SymbolKind) { + case SymbolKind.Namespace: + return new[] { GetSearchScopeForNamespace((INamespace)symbol) }; + case SymbolKind.TypeParameter: + return new[] { GetSearchScopeForTypeParameter((ITypeParameter)symbol) }; + // TODO: IVariable etc. + } + IEntity entity = symbol as IEntity; if (entity == null) - throw new ArgumentNullException("entity"); + throw new NotSupportedException("Unsupported symbol type"); if (entity is IMember) entity = NormalizeMember((IMember)entity); Accessibility effectiveAccessibility = GetEffectiveAccessibility(entity); - ITypeDefinition topLevelTypeDefinition = entity.DeclaringTypeDefinition; - while (topLevelTypeDefinition != null && topLevelTypeDefinition.DeclaringTypeDefinition != null) - topLevelTypeDefinition = topLevelTypeDefinition.DeclaringTypeDefinition; + var topLevelTypeDefinition = GetTopLevelTypeDefinition(entity); SearchScope scope; SearchScope additionalScope = null; switch (entity.SymbolKind) { @@ -289,13 +298,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - public IList GetSearchScopes(INamespace ns) + public IList GetSearchScopes(IEnumerable symbols) { - if (ns == null) - throw new ArgumentNullException("ns"); - return new[] { GetSearchScopeForNamespace(ns) }; + if (symbols == null) + throw new ArgumentNullException("symbols"); + return symbols.SelectMany(GetSearchScopes).ToList(); + } + + static ITypeDefinition GetTopLevelTypeDefinition(IEntity entity) + { + if (entity == null) + return null; + ITypeDefinition topLevelTypeDefinition = entity.DeclaringTypeDefinition; + while (topLevelTypeDefinition != null && topLevelTypeDefinition.DeclaringTypeDefinition != null) + topLevelTypeDefinition = topLevelTypeDefinition.DeclaringTypeDefinition; + return topLevelTypeDefinition; } - #endregion #region GetInterestingFileNames @@ -360,6 +378,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region FindReferencesInFile + /// + /// Finds all references in the given file. + /// + /// The search scope for which to look. + /// AST resolver for the file to search in. + /// Callback used to report the references that were found. + /// CancellationToken that may be used to cancel the operation. + public void FindReferencesInFile(IFindReferenceSearchScope searchScope, CSharpAstResolver resolver, + FoundReferenceCallback callback, CancellationToken cancellationToken) + { + if (resolver == null) + throw new ArgumentNullException("resolver"); + FindReferencesInFile(searchScope, resolver.UnresolvedFile, (SyntaxTree)resolver.RootNode, resolver.Compilation, callback, cancellationToken); + } + + /// + /// Finds all references in the given file. + /// + /// The search scopes for which to look. + /// AST resolver for the file to search in. + /// Callback used to report the references that were found. + /// CancellationToken that may be used to cancel the operation. + public void FindReferencesInFile(IList searchScopes, CSharpAstResolver resolver, + FoundReferenceCallback callback, CancellationToken cancellationToken) + { + if (resolver == null) + throw new ArgumentNullException("resolver"); + FindReferencesInFile(searchScopes, resolver.UnresolvedFile, (SyntaxTree)resolver.RootNode, resolver.Compilation, callback, cancellationToken); + } + /// /// Finds all references in the given file. /// @@ -424,6 +472,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } #endregion + #region RenameReferencesInFile + public void RenameReferencesInFile(IList searchScopes, string newName, CSharpAstResolver resolver, + Action callback, Action errorCallback, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + #endregion + #region Find TypeDefinition References SearchScope FindTypeDefinitionReferences(ITypeDefinition typeDefinition, bool findTypeReferencesEvenIfAliased, out SearchScope additionalScope) { @@ -843,8 +899,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver var arr = rr as AwaitResolveResult; if (arr != null) { return IsMatch(arr.GetAwaiterInvocation) - || (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true)) - || (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true)); + || (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true)) + || (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true)); } } var mrr = rr as MemberResolveResult; @@ -1090,7 +1146,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver internal override bool IsMatch(ResolveResult rr) { ConversionResolveResult crr = rr as ConversionResolveResult; - return crr != null && crr.Conversion.IsUserDefined + return crr != null && crr.Conversion.IsUserDefined && findReferences.IsMemberMatch(op, crr.Conversion.Method, crr.Conversion.IsVirtualMethodLookup); } } @@ -1282,8 +1338,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// The compilation. /// Callback used to report the references that were found. /// Cancellation token that may be used to cancel the operation. + [Obsolete("Use GetSearchScopes(typeParameter) instead")] public void FindTypeParameterReferences(IType typeParameter, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, - ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken) + ICompilation compilation, FoundReferenceCallback callback, CancellationToken cancellationToken) { if (typeParameter == null) throw new ArgumentNullException("typeParameter"); @@ -1295,6 +1352,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver FindReferencesInFile(searchScope, unresolvedFile, syntaxTree, compilation, callback, cancellationToken); } + SearchScope GetSearchScopeForTypeParameter(ITypeParameter tp) + { + var searchScope = new SearchScope(c => new FindTypeParameterReferencesNavigator(tp)); + var compilationProvider = tp as ICompilationProvider; + if (compilationProvider != null) + searchScope.declarationCompilation = compilationProvider.Compilation; + searchScope.topLevelTypeDefinition = GetTopLevelTypeDefinition(tp.Owner); + searchScope.accessibility = Accessibility.Private; + return searchScope; + } + class FindTypeParameterReferencesNavigator : FindReferenceNavigator { readonly ITypeParameter typeParameter; @@ -1322,14 +1390,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } #endregion - + #region Find Namespace References SearchScope GetSearchScopeForNamespace(INamespace ns) { var scope = new SearchScope ( delegate (ICompilation compilation) { - return new FindNamespaceNavigator (ns); - } + return new FindNamespaceNavigator (ns); + } ); return scope; } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/RenameCallbackArguments.cs b/ICSharpCode.NRefactory.CSharp/Resolver/RenameCallbackArguments.cs new file mode 100644 index 0000000000..9be51621b5 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Resolver/RenameCallbackArguments.cs @@ -0,0 +1,31 @@ +/* + * Created by SharpDevelop. + * User: Daniel + * Date: 6/13/2013 + * Time: 17:50 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System; + +namespace ICSharpCode.NRefactory.CSharp.Resolver +{ + /// + /// Arguments for the callback of . + /// + public class RenameCallbackArguments + { + public AstNode NodeToReplace { get; private set; } + public AstNode NewNode { get; private set; } + + public RenameCallbackArguments(AstNode nodeToReplace, AstNode newNode) + { + if (nodeToReplace == null) + throw new ArgumentNullException("nodeToReplace"); + if (newNode == null) + throw new ArgumentNullException("newNode"); + this.NodeToReplace = nodeToReplace; + this.NewNode = newNode; + } + } +} From 444eb111536b1e216a5ada30013967188b8ae6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 14 Jun 2013 10:46:40 +0200 Subject: [PATCH 08/12] Implemented basic rename feature. --- .../Resolver/FindReferences.cs | 70 ++++++++++++- .../Analysis/SymbolCollectorTests.cs | 41 ++++++++ .../CSharp/Resolver/FindReferencesTest.cs | 97 +++++++++++++++++++ .../ICSharpCode.NRefactory.Tests.csproj | 4 +- ...{MemberCollector.cs => SymbolCollector.cs} | 6 +- .../ICSharpCode.NRefactory.csproj | 3 +- 6 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs rename ICSharpCode.NRefactory/Analysis/{MemberCollector.cs => SymbolCollector.cs} (88%) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs index 495d2f91e6..a291036f54 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs @@ -473,10 +473,76 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver #endregion #region RenameReferencesInFile + + AstNode GetNodeToReplace(AstNode node) + { + if (node is ConstructorInitializer) + return null; + if (node is ObjectCreateExpression) + node = ((ObjectCreateExpression)node).Type; + + if (node is InvocationExpression) + node = ((InvocationExpression)node).Target; + + if (node is MemberReferenceExpression) + node = ((MemberReferenceExpression)node).MemberNameToken; + + if (node is SimpleType) + node = ((SimpleType)node).IdentifierToken; + + if (node is MemberType) + node = ((MemberType)node).MemberNameToken; + + if (node is NamespaceDeclaration) { +// var nsd = ((NamespaceDeclaration)node); +// node = nsd.Identifiers.LastOrDefault (n => n.Name == memberName) ?? nsd.Identifiers.FirstOrDefault (); +// if (node == null) + return null; + } + + if (node is TypeDeclaration) + node = ((TypeDeclaration)node).NameToken; + if (node is DelegateDeclaration) + node = ((DelegateDeclaration)node).NameToken; + + if (node is EntityDeclaration) + node = ((EntityDeclaration)node).NameToken; + + if (node is ParameterDeclaration) + node = ((ParameterDeclaration)node).NameToken; + if (node is ConstructorDeclaration) + node = ((ConstructorDeclaration)node).NameToken; + if (node is DestructorDeclaration) + node = ((DestructorDeclaration)node).NameToken; + if (node is NamedArgumentExpression) + node = ((NamedArgumentExpression)node).NameToken; + if (node is NamedExpression) + node = ((NamedExpression)node).NameToken; + if (node is VariableInitializer) + node = ((VariableInitializer)node).NameToken; + + if (node is IdentifierExpression) { + node = ((IdentifierExpression)node).IdentifierToken; + } + return node; + } + public void RenameReferencesInFile(IList searchScopes, string newName, CSharpAstResolver resolver, - Action callback, Action errorCallback, CancellationToken cancellationToken) + Action callback, Action errorCallback, CancellationToken cancellationToken = default (CancellationToken)) { - throw new NotImplementedException(); + WholeVirtualSlot = true; + FindReferencesInFile( + searchScopes, + resolver, + delegate(AstNode astNode, ResolveResult result) { + var nodeToReplace = GetNodeToReplace(astNode); + if (nodeToReplace == null) { + errorCallback (new Error (ErrorType.Error, "no node to replace found.")); + return; + } + callback (new RenameCallbackArguments(nodeToReplace, Identifier.Create(newName))); + }, + cancellationToken); } #endregion diff --git a/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs new file mode 100644 index 0000000000..7675c03ec0 --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs @@ -0,0 +1,41 @@ +// +// SymbolCollectorTests.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com) +// +// 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.Linq; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.TypeSystem; +using NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.CodeCompletion; + +namespace ICSharpCode.NRefactory.Analysis +{ + [TestFixture] + public class SymbolCollectorTests + { + + } +} + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs index d01c48826b..08bc38a260 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs @@ -24,6 +24,9 @@ using System.Threading; using ICSharpCode.NRefactory.CSharp.TypeSystem; using ICSharpCode.NRefactory.TypeSystem; using NUnit.Framework; +using ICSharpCode.NRefactory.Analysis; +using System.Text; +using ICSharpCode.NRefactory.Editor; namespace ICSharpCode.NRefactory.CSharp.Resolver { @@ -383,5 +386,99 @@ namespace Foo Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 12 && r is SimpleType)); } #endregion + + #region Rename + + ISymbol GetSymbol (string reflectionName) + { + Stack typeStack = new Stack(compilation.MainAssembly.TopLevelTypeDefinitions); + while (typeStack.Count > 0) { + var cur = typeStack.Pop(); + if (cur.ReflectionName == reflectionName) + return cur; + foreach (var member in cur.Members) + if (member.ReflectionName == reflectionName) + return member; + foreach (var nested in cur.NestedTypes) { + typeStack.Push(nested); + } + } + return null; + } + + IList Rename(string fullyQualifiedName, string newName, bool includeOverloads) + { + var sym = GetSymbol(fullyQualifiedName); + Assert.NotNull(sym); + var graph = new TypeGraph(compilation.Assemblies); + + var scopes = findReferences.GetSearchScopes(SymbolCollector.GetRelatedSymbols(graph, sym, includeOverloads)); + List result = new List(); + + findReferences.RenameReferencesInFile( + scopes, + newName, + new CSharpAstResolver(compilation, syntaxTree, unresolvedFile), + delegate(RenameCallbackArguments obj) { + result.Add (obj.NodeToReplace); + }, + delegate(Error obj) { + + }); + return result; + } + + void TestRename(string code, string symbolName) + { + StringBuilder sb = new StringBuilder(); + List offsets = new List(); + foreach (var ch in code) { + if (ch == '$') { + offsets.Add(sb.Length); + continue; + } + sb.Append(ch); + } + Init(sb.ToString ()); + var doc = new ReadOnlyDocument(sb.ToString ()); + var result = Rename(symbolName, "x", false); + Assert.AreEqual(offsets.Count, result.Count); + + result.Select(r => doc.GetOffset (r.StartLocation)).SequenceEqual(offsets); + } + + [Test] + public void TestSimpleRename () + { + TestRename (@"using System; +class $Test { + $Test test; +}", "Test"); + } + + + [Test] + public void TestOverride () + { + TestRename(@"using System; +class Test { + public virtual int $Foo { get; set; } +} + +class Test2 : Test { + public override int $Foo { get; set; } +} + +class Test3 : Test { + public override int $Foo { get; set; } + public FindReferencesTest () + { + $Foo = 4; + } +} +", "Test.Foo"); + } + + #endregion } } diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 1b40722578..8bf7a1b19a 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -417,6 +417,7 @@ + @@ -439,9 +440,6 @@ False - - - diff --git a/ICSharpCode.NRefactory/Analysis/MemberCollector.cs b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs similarity index 88% rename from ICSharpCode.NRefactory/Analysis/MemberCollector.cs rename to ICSharpCode.NRefactory/Analysis/SymbolCollector.cs index d0fcc40bbe..186f20488b 100644 --- a/ICSharpCode.NRefactory/Analysis/MemberCollector.cs +++ b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs @@ -22,11 +22,11 @@ using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.Analysis { - public class MemberCollector + public class SymbolCollector { - public static IEnumerable GetRelatedMembers(TypeGraph g, IMember m, bool includeOverloads) + public static IEnumerable GetRelatedSymbols(TypeGraph g, ISymbol m, bool includeOverloads) { - throw new NotImplementedException(); + yield return m; } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 00041d86d7..2df94728d8 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -83,7 +83,6 @@ - @@ -279,10 +278,10 @@ + - From 1f2f3691beda537ba7f2c2f6a6a7cf580dec30c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 14 Jun 2013 12:00:48 +0200 Subject: [PATCH 09/12] Fixed possible parser exception. --- ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs index b9ff324f8f..488129c3f1 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs @@ -2699,7 +2699,7 @@ namespace ICSharpCode.NRefactory.CSharp direction.AddChild ((Expression)arg.Expr.Accept (this), Roles.Expression); newArg.AddChild (direction, Roles.Expression); } else { - newArg.AddChild ((Expression)na.Expr.Accept (this), Roles.Expression); + newArg.AddChild (na.Expr != null ? (Expression)na.Expr.Accept (this) : new ErrorExpression ("Named argument expression parse error"), Roles.Expression); } return newArg; } From 5b9e640160dfb56a0eea0145068d7a601215246a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 14 Jun 2013 12:47:57 +0200 Subject: [PATCH 10/12] Implemented first version of the symbol collector. --- .../Analysis/SymbolCollectorTests.cs | 162 ++++++++++++++++++ .../CSharp/Resolver/FindReferencesTest.cs | 4 +- .../Analysis/SymbolCollector.cs | 104 ++++++++++- 3 files changed, 266 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs index 7675c03ec0..9ced7ed7ab 100644 --- a/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs +++ b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs @@ -29,6 +29,10 @@ using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.TypeSystem; using NUnit.Framework; using ICSharpCode.NRefactory.CSharp.CodeCompletion; +using System.Text; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.CSharp.Resolver; namespace ICSharpCode.NRefactory.Analysis { @@ -36,6 +40,164 @@ namespace ICSharpCode.NRefactory.Analysis public class SymbolCollectorTests { + void CollectMembers(string code, string memberName, bool includeOverloads = true) + { + StringBuilder sb = new StringBuilder(); + List offsets = new List(); + foreach (var ch in code) { + if (ch == '$') { + offsets.Add(sb.Length); + continue; + } + sb.Append(ch); + } + var syntaxTree = SyntaxTree.Parse(sb.ToString (), "test.cs"); + var unresolvedFile = syntaxTree.ToTypeSystem(); + var compilation = TypeSystemHelper.CreateCompilation(unresolvedFile); + + var symbol = FindReferencesTest.GetSymbol(compilation, memberName); + + var result = SymbolCollector.GetRelatedSymbols (new TypeGraph (compilation.Assemblies), + symbol, includeOverloads); + if (offsets.Count != result.Count()) { + foreach (var a in result) + Console.WriteLine(a); + } + Assert.AreEqual(offsets.Count, result.Count()); + var doc = new ReadOnlyDocument(sb.ToString ()); + result + .Select(r => doc.GetOffset ((r as IEntity).Region.Begin)) + .SequenceEqual(offsets); + } + + [Test] + public void TestSingleInterfaceImpl () + { + var code = @" +interface IA +{ + void $Method(); +} + +class A : IA +{ + public virtual void $Method() { }; +} + +class B : A +{ + public override void Method() { }; +} + +class C : IA +{ + public void $Method() { }; +}"; + CollectMembers(code, "IA.Method"); + } + + + [Test] + public void TestMultiInterfacesImpl1 () + { + var code = @" +interface IA +{ + void $Method(); +} +interface IB +{ + void $Method(); +} +class A : IA, IB +{ + public void $Method() { } +} +class B : IA +{ + public void $Method() { } +} +class C : IB +{ + public void $Method() { } +}"; + CollectMembers(code, "A.Method"); + } + + + [Test] + public void TestOverloads () + { + var code = @" +class A +{ + public void $Method () { } + public void $Method (int i) { } + public void $Method (string i) { } +} +"; + CollectMembers(code, "A.Method"); + } + + [Test] + public void TestConstructor () + { + var code = @" +class $A +{ + public $A() { } + public $A(int i) { } +} +"; + CollectMembers(code, "A"); + } + + + [Test] + public void TestDestructor () + { + var code = @" +class $A +{ + $~A() { } +} +"; + CollectMembers(code, "A"); + } + + [Test] + public void TestStaticConstructor () + { + var code = @" +class $A +{ + static $A() { } + public $A(int i) { } +} +"; + CollectMembers(code, "A"); + } + + [Test] + public void TestShadowedMember () + { + var code = @" +class A +{ + public int $Prop + { get; set; } +} +class B : A +{ + public int Prop + { get; set; } +} +"; + CollectMembers(code, "A.Prop"); + } + + + } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs index 08bc38a260..a62eda24bf 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs @@ -389,7 +389,7 @@ namespace Foo #region Rename - ISymbol GetSymbol (string reflectionName) + internal static ISymbol GetSymbol (ICompilation compilation, string reflectionName) { Stack typeStack = new Stack(compilation.MainAssembly.TopLevelTypeDefinitions); while (typeStack.Count > 0) { @@ -408,7 +408,7 @@ namespace Foo IList Rename(string fullyQualifiedName, string newName, bool includeOverloads) { - var sym = GetSymbol(fullyQualifiedName); + var sym = GetSymbol(compilation, fullyQualifiedName); Assert.NotNull(sym); var graph = new TypeGraph(compilation.Assemblies); diff --git a/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs index 186f20488b..ebf2b353e4 100644 --- a/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs +++ b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team +// Copyright (c) 2013 AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software @@ -19,14 +19,114 @@ using System; using System.Collections.Generic; using ICSharpCode.NRefactory.TypeSystem; +using System.Linq; namespace ICSharpCode.NRefactory.Analysis { + /// + /// The symbol collector collects related symbols that form a group of symbols that should be renamed + /// when a name of one symbol changes. For example if a type definition name should be changed + /// the constructors and destructor names should change as well. + /// public class SymbolCollector { + static IEnumerable CollectTypeRelatedMembers (ITypeDefinition type) + { + yield return type; + foreach (var c in type.GetDefinition ().GetMembers (m => !m.IsSynthetic && (m.SymbolKind == SymbolKind.Constructor || m.SymbolKind == SymbolKind.Destructor), GetMemberOptions.IgnoreInheritedMembers)) { + yield return c; + } + } + + static IEnumerable CollectOverloads (TypeGraph g, IMethod method) + { + return method.DeclaringType + .GetMethods (m => m.Name == method.Name) + .Where (m => m != method); + } + + static IMember SearchMember (ITypeDefinition derivedType, IMember method) + { + foreach (var m in derivedType.Members) { + if (m.ImplementedInterfaceMembers.Contains (method)) + return m; + } + return null; + } + + static IEnumerable MakeUnique (List symbols) + { + HashSet taken = new HashSet (); + foreach (var sym in symbols) { + if (taken.Contains (sym)) + continue; + taken.Add (sym); + yield return sym; + } + } + + /// + /// Gets the related symbols. + /// + /// The related symbols. + /// The type graph. + /// The symbol to search + /// If set to true overloads are included in the rename. public static IEnumerable GetRelatedSymbols(TypeGraph g, ISymbol m, bool includeOverloads) { - yield return m; + switch (m.SymbolKind) { + case SymbolKind.TypeDefinition: + return CollectTypeRelatedMembers ((ITypeDefinition)m); + + case SymbolKind.Field: + case SymbolKind.Operator: + case SymbolKind.Variable: + case SymbolKind.Parameter: + case SymbolKind.TypeParameter: + return new ISymbol[] { m }; + + case SymbolKind.Constructor: + case SymbolKind.Destructor: + return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition, includeOverloads); + + case SymbolKind.Indexer: + case SymbolKind.Event: + case SymbolKind.Property: + return new ISymbol[] { m }; + + case SymbolKind.Method: + var method = (IMethod)m; + List symbols = new List (); + if (method.ImplementedInterfaceMembers.Count > 0) { + foreach (var m2 in method.ImplementedInterfaceMembers) { + symbols.AddRange (GetRelatedSymbols (g, m2, includeOverloads)); + } + } else { + symbols.Add (method); + } + + if (method.DeclaringType.Kind == TypeKind.Interface) { + foreach (var derivedType in g.GetNode (method.DeclaringTypeDefinition).DerivedTypes) { + var member = SearchMember (derivedType.TypeDefinition, method); + if (member != null) + symbols.Add (member); + } + } + + + if (includeOverloads) { + foreach (var m3 in CollectOverloads (g, method)) { + symbols.AddRange (GetRelatedSymbols (g, m3, false)); + } + } + return MakeUnique (symbols); + + case SymbolKind.Namespace: + // TODO? + return new ISymbol[] { m }; + default: + throw new ArgumentOutOfRangeException ("symbol:"+m.SymbolKind); + } } } } From 23636398d0a4cccf70e163b679958bfc9a16640a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 14 Jun 2013 13:10:56 +0200 Subject: [PATCH 11/12] Symbol collector is now more generic and can be used to find overloads for find references as well. --- .../Analysis/SymbolCollectorTests.cs | 7 +++- .../CSharp/Resolver/FindReferencesTest.cs | 6 ++- .../Analysis/SymbolCollector.cs | 37 ++++++++++++++++--- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs index 9ced7ed7ab..74a3bb9e84 100644 --- a/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs +++ b/ICSharpCode.NRefactory.Tests/Analysis/SymbolCollectorTests.cs @@ -56,9 +56,12 @@ namespace ICSharpCode.NRefactory.Analysis var compilation = TypeSystemHelper.CreateCompilation(unresolvedFile); var symbol = FindReferencesTest.GetSymbol(compilation, memberName); + var col = new SymbolCollector(); + col.IncludeOverloads = includeOverloads; + col.GroupForRenaming = true; - var result = SymbolCollector.GetRelatedSymbols (new TypeGraph (compilation.Assemblies), - symbol, includeOverloads); + var result = col.GetRelatedSymbols (new TypeGraph (compilation.Assemblies), + symbol); if (offsets.Count != result.Count()) { foreach (var a in result) Console.WriteLine(a); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs index a62eda24bf..f71d0a9f65 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs @@ -411,8 +411,10 @@ namespace Foo var sym = GetSymbol(compilation, fullyQualifiedName); Assert.NotNull(sym); var graph = new TypeGraph(compilation.Assemblies); - - var scopes = findReferences.GetSearchScopes(SymbolCollector.GetRelatedSymbols(graph, sym, includeOverloads)); + var col = new SymbolCollector(); + col.IncludeOverloads = includeOverloads; + col.GroupForRenaming = true; + var scopes = findReferences.GetSearchScopes(col.GetRelatedSymbols(graph, sym)); List result = new List(); findReferences.RenameReferencesInFile( diff --git a/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs index ebf2b353e4..fdd7408d08 100644 --- a/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs +++ b/ICSharpCode.NRefactory/Analysis/SymbolCollector.cs @@ -30,6 +30,20 @@ namespace ICSharpCode.NRefactory.Analysis /// public class SymbolCollector { + /// + /// Gets or sets a value indicating whether this should include overloads. + /// + /// true if overloads should be included; otherwise, false. + public bool IncludeOverloads { + get; + set; + } + + public bool GroupForRenaming { + get; + set; + } + static IEnumerable CollectTypeRelatedMembers (ITypeDefinition type) { yield return type; @@ -72,7 +86,7 @@ namespace ICSharpCode.NRefactory.Analysis /// The type graph. /// The symbol to search /// If set to true overloads are included in the rename. - public static IEnumerable GetRelatedSymbols(TypeGraph g, ISymbol m, bool includeOverloads) + public IEnumerable GetRelatedSymbols(TypeGraph g, ISymbol m) { switch (m.SymbolKind) { case SymbolKind.TypeDefinition: @@ -86,8 +100,20 @@ namespace ICSharpCode.NRefactory.Analysis return new ISymbol[] { m }; case SymbolKind.Constructor: + if (GroupForRenaming) + return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); + List constructorSymbols = new List (); + if (IncludeOverloads) { + foreach (var m3 in CollectOverloads (g, (IMethod)m)) { + constructorSymbols.Add (m3); + } + } + return constructorSymbols; + case SymbolKind.Destructor: - return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition, includeOverloads); + if (GroupForRenaming) + return GetRelatedSymbols (g, ((IMethod)m).DeclaringTypeDefinition); + return new ISymbol[] { m }; case SymbolKind.Indexer: case SymbolKind.Event: @@ -99,7 +125,7 @@ namespace ICSharpCode.NRefactory.Analysis List symbols = new List (); if (method.ImplementedInterfaceMembers.Count > 0) { foreach (var m2 in method.ImplementedInterfaceMembers) { - symbols.AddRange (GetRelatedSymbols (g, m2, includeOverloads)); + symbols.AddRange (GetRelatedSymbols (g, m2)); } } else { symbols.Add (method); @@ -114,9 +140,10 @@ namespace ICSharpCode.NRefactory.Analysis } - if (includeOverloads) { + if (IncludeOverloads) { + IncludeOverloads = false; foreach (var m3 in CollectOverloads (g, method)) { - symbols.AddRange (GetRelatedSymbols (g, m3, false)); + symbols.AddRange (GetRelatedSymbols (g, m3)); } } return MakeUnique (symbols); From bbcde1ea2e9de8530c1653798215cf6f25f9ea2b Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 14 Jun 2013 13:19:41 +0200 Subject: [PATCH 12/12] Use ISymbol in Script.Rename() --- .../InconsistentNamingIssue.cs | 12 ++--- .../CodeIssues/TypeParameterNotUsedIssue.cs | 8 ++-- .../Refactoring/Script.cs | 45 ++----------------- .../Resolver/FindReferences.cs | 3 +- .../CodeActions/TestRefactoringContext.cs | 20 +++------ .../CSharp/Resolver/FindReferencesTest.cs | 1 + 6 files changed, 24 insertions(+), 65 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs index b39f677805..8cf6944695 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs @@ -147,11 +147,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (resolveResult is MemberResolveResult) { script.Rename(((MemberResolveResult)resolveResult).Member, n); } else if (resolveResult is TypeResolveResult) { - var def = ((TypeResolveResult)resolveResult).Type.GetDefinition(); + var def = resolveResult.Type.GetDefinition(); if (def != null) { script.Rename(def, n); - } else { - script.RenameTypeParameter(((TypeResolveResult)resolveResult).Type, n); + } else if (resolveResult.Type.Kind == TypeKind.TypeParameter) { + script.Rename((ITypeParameter)resolveResult.Type, n); } } else if (resolveResult is LocalResolveResult) { script.Rename(((LocalResolveResult)resolveResult).Variable, n); @@ -169,11 +169,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring if (resolveResult is MemberResolveResult) { script.Rename(((MemberResolveResult)resolveResult).Member); } else if (resolveResult is TypeResolveResult) { - var def = ((TypeResolveResult)resolveResult).Type.GetDefinition(); + var def = resolveResult.Type.GetDefinition(); if (def != null) { script.Rename(def); - } else { - script.RenameTypeParameter(((TypeResolveResult)resolveResult).Type); + } else if (resolveResult.Type.Kind == TypeKind.TypeParameter) { + script.Rename((ITypeParameter)resolveResult.Type); } } else if (resolveResult is LocalResolveResult) { script.Rename(((LocalResolveResult)resolveResult).Variable); diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/TypeParameterNotUsedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/TypeParameterNotUsedIssue.cs index 85e6e88a49..ee980ddd92 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/TypeParameterNotUsedIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/TypeParameterNotUsedIssue.cs @@ -52,13 +52,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring } protected static bool FindUsage (BaseRefactoringContext context, SyntaxTree unit, - ITypeParameter typaParameter, AstNode declaration) + ITypeParameter typeParameter, AstNode declaration) { var found = false; - refFinder.FindTypeParameterReferences (typaParameter, context.UnresolvedFile, unit, context.Compilation, + var searchScopes = refFinder.GetSearchScopes(typeParameter); + refFinder.FindReferencesInFile(searchScopes, context.Resolver, (node, resolveResult) => { - found = found || node != declaration; + if (node != declaration) + found = true; }, context.CancellationToken); return found; } diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs index 3c9015958a..b133b22287 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs @@ -346,55 +346,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring } /// - /// Renames the specified entity. + /// Renames the specified symbol. /// - /// - /// The Entity to rename + /// + /// The symbol to rename /// /// /// The new name, if null the user is prompted for a new name. /// - public virtual void Rename(IEntity entity, string name = null) + public virtual void Rename(ISymbol symbol, string name = null) { } - /// - /// Renames the specified entity. - /// - /// - /// The Entity to rename - /// - /// - /// The new name, if null the user is prompted for a new name. - /// - public virtual void RenameTypeParameter (IType type, string name = null) - { - } - - /// - /// Renames the specified variable. - /// - /// - /// The Variable to rename - /// - /// - /// The new name, if null the user is prompted for a new name. - /// - public virtual void Rename(IVariable variable, string name = null) - { - } - - /// - /// Renames the specified namespace. - /// - /// The namespace - /// - /// The new name, if null the user is prompted for a new name. - /// - public virtual void Rename(INamespace ns, string name = null) - { - } - public virtual void DoGlobalOperationOn(IEntity entity, Action callback, string operationDescripton = null) { } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs index a291036f54..1f0afa1037 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs @@ -396,7 +396,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// /// Finds all references in the given file. /// - /// The search scopes for which to look. + /// The search scopes for which to look. /// AST resolver for the file to search in. /// Callback used to report the references that were found. /// CancellationToken that may be used to cancel the operation. @@ -530,7 +530,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public void RenameReferencesInFile(IList searchScopes, string newName, CSharpAstResolver resolver, Action callback, Action errorCallback, CancellationToken cancellationToken = default (CancellationToken)) { - WholeVirtualSlot = true; FindReferencesInFile( searchScopes, resolver, diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs index 388458ceda..5a0e9f346b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs @@ -165,17 +165,21 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions Replace (node, new IdentifierExpression (newName)); } - public override void Rename (IEntity entity, string name) + public override void Rename (ISymbol symbol, string name) { + if (symbol.SymbolKind == SymbolKind.Variable || symbol.SymbolKind == SymbolKind.Parameter) { + Rename(symbol as IVariable, name); + return; + } FindReferences refFinder = new FindReferences (); - refFinder.FindReferencesInFile (refFinder.GetSearchScopes (entity), + refFinder.FindReferencesInFile (refFinder.GetSearchScopes (symbol), context.UnresolvedFile, context.RootNode as SyntaxTree, context.Compilation, (n, r) => Rename (n, name), context.CancellationToken); } - public override void Rename (IVariable variable, string name) + void Rename (IVariable variable, string name) { FindReferences refFinder = new FindReferences (); refFinder.FindLocalReferences (variable, @@ -185,16 +189,6 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions context.CancellationToken); } - public override void RenameTypeParameter (IType type, string name = null) - { - FindReferences refFinder = new FindReferences (); - refFinder.FindTypeParameterReferences (type, - context.UnresolvedFile, - context.RootNode as SyntaxTree, - context.Compilation, (n, r) => Rename (n, name), - context.CancellationToken); - } - public override void CreateNewType (AstNode newType, NewTypeContext context) { var output = OutputNode (0, newType, true); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs index f71d0a9f65..033acf7fc1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs @@ -442,6 +442,7 @@ namespace Foo sb.Append(ch); } Init(sb.ToString ()); + findReferences.WholeVirtualSlot = true; var doc = new ReadOnlyDocument(sb.ToString ()); var result = Rename(symbolName, "x", false); Assert.AreEqual(offsets.Count, result.Count);