diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 09463aeed6..2a1aa591af 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -278,7 +278,6 @@ - @@ -535,6 +534,9 @@ + + + @@ -543,16 +545,7 @@ - - - - - - - - - - + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs deleted file mode 100644 index 0d18436be4..0000000000 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs +++ /dev/null @@ -1,100 +0,0 @@ - -// ConvertToStaticMethodAction.cs -// -// Author: -// Ciprian Khlud -// -// Copyright (c) 2013 Ciprian Khlud -// -// 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.Collections.Generic; -using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory.Semantics; -using System.Linq; -using ICSharpCode.NRefactory.TypeSystem; - -namespace ICSharpCode.NRefactory.CSharp.Refactoring -{ - [ContextAction("Make this method static", Description = "This method doesn't use any non static members so it can be made static")] - public class ConvertToStaticMethodAction : ICodeActionProvider - { - public IEnumerable GetActions(RefactoringContext context) - { - // TODO: Invert if without else - // ex. if (cond) DoSomething () == if (!cond) return; DoSomething () - // beware of loop contexts return should be continue then. - var methodDeclaration = GetMethodDeclaration(context); - if (methodDeclaration == null) - yield break; - - var resolved = context.Resolve(methodDeclaration) as MemberResolveResult; - if (resolved == null) - yield break; - var isImplementingInterface = resolved.Member.ImplementedInterfaceMembers.Any(); - - if (isImplementingInterface) - yield break; - yield return new CodeAction(context.TranslateString(string.Format("Make '{0}' static", methodDeclaration.Name)), script => - { - var clonedDeclaration = (MethodDeclaration)methodDeclaration.Clone(); - clonedDeclaration.Modifiers |= Modifiers.Static; - script.Replace(methodDeclaration, clonedDeclaration); - var rr = context.Resolve (methodDeclaration) as MemberResolveResult; - var method = (IMethod)rr.Member; - //method.ImplementedInterfaceMembers.Any(m => methodGroupResolveResult.Methods.Contains((IMethod)m)); - - script.DoGlobalOperationOn(rr.Member, (fctx, fscript, fnode) => { - if (fnode is MemberReferenceExpression) { - var memberReference = new MemberReferenceExpression ( - new TypeReferenceExpression (fctx.CreateShortType (rr.Member.DeclaringType)), - rr.Member.Name - ); - fscript.Replace (fnode, memberReference); - } else if (fnode is InvocationExpression) { - var invoke = (InvocationExpression)fnode; - if (!(invoke.Target is MemberReferenceExpression)) - return; - var memberReference = new MemberReferenceExpression ( - new TypeReferenceExpression (fctx.CreateShortType (rr.Member.DeclaringType)), - rr.Member.Name - ); - fscript.Replace (invoke.Target, memberReference); - } - }); - }, methodDeclaration); - } - - static MethodDeclaration GetMethodDeclaration(RefactoringContext context) - { - var result = context.GetNode (); - if (result == null) - return null; - //unsafe transformation for now. For all other public instances the code should - //replace the variable.Call(...) to ClassName.Call() - const Modifiers ignoredModifiers = Modifiers.Override | Modifiers.Virtual | Modifiers.Static; - if ((result.Modifiers & ignoredModifiers) != 0) - return null; - - var usesNonStatic = StaticVisitor.UsesNotStaticMember(context, result); - if (usesNonStatic) return null; - return result; - } - } -} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveFieldRefactoryActionRefactoringAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveFieldRefactoryActionRefactoringAction.cs new file mode 100644 index 0000000000..7f44799942 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveFieldRefactoryActionRefactoringAction.cs @@ -0,0 +1,110 @@ +// +// RemoveField.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using ICSharpCode.NRefactory.CSharp.Refactoring; +using System.Collections.Generic; +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.Semantics; + +namespace ICSharpCode.NRefactory.CSharp +{ + [ContextAction("Removes a field from a class", Description = "It removes also the empty assingments and the usages")] + public class RemoveFieldRefactoryAction : ICodeActionProvider + { + public IEnumerable GetActions(RefactoringContext context) + { + var fieldDeclaration = GetFieldDeclaration(context); + if(fieldDeclaration==null) + yield break; + + + yield return new CodeAction(string.Format(context.TranslateString("Remove field '{0}'"), fieldDeclaration.Name) + , script => GenerateNewScript( + script, fieldDeclaration, context), fieldDeclaration); + } + + + void GenerateNewScript(Script script, FieldDeclaration fieldDeclaration, RefactoringContext context) + { + var firstOrNullObject = fieldDeclaration.Variables.FirstOrNullObject(); + if(firstOrNullObject==null) + return; + var matchedNodes = ComputeMatchNodes(context, firstOrNullObject); + + foreach (var matchNode in matchedNodes) + { + var parent = matchNode.Parent; + if (matchNode is VariableInitializer) + { + script.Remove(parent); + } + else + if (matchNode is IdentifierExpression) + { + if(parent is AssignmentExpression) + { + script.Remove(parent.Parent); + } + else + { + var clone = (IdentifierExpression)matchNode.Clone(); + clone.Identifier = "TODO"; + script.Replace(matchNode, clone); + } + } + } + } + + private static List ComputeMatchNodes(RefactoringContext context, VariableInitializer firstOrNullObject) + { + var referenceFinder = new FindReferences(); + var matchedNodes = new List(); + + var resolveResult = context.Resolver.Resolve(firstOrNullObject); + var member = resolveResult as MemberResolveResult; + if (member == null)//not a member is unexpected case, so is better to return no match than to break the code + return matchedNodes; + + FoundReferenceCallback callback = (matchNode, result) => matchedNodes.Add(matchNode); + + var searchScopes = referenceFinder.GetSearchScopes(member.Member); + referenceFinder.FindReferencesInFile(searchScopes, + context.UnresolvedFile, + context.RootNode as SyntaxTree, + context.Compilation, callback, + context.CancellationToken); + return matchedNodes; + } + + FieldDeclaration GetFieldDeclaration(RefactoringContext context) + { + var result = context.GetNode(); + + return result; + } + } +} + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConstructorIssues/PublicConstructorInAbstractClass.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConstructorIssues/PublicConstructorInAbstractClass.cs index 8172d7844d..07a131afd0 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConstructorIssues/PublicConstructorInAbstractClass.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConstructorIssues/PublicConstructorInAbstractClass.cs @@ -68,9 +68,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) { if (constructorDeclaration.HasModifier (Modifiers.Public)) { - AddIssue(constructorDeclaration.NameToken, ctx.TranslateString("Convert public to protected"), script => { - script.Replace(constructorDeclaration.ModifierTokens.First (t => t.Modifier == Modifiers.Public), new CSharpModifierToken(TextLocation.Empty, Modifiers.Protected)); - }); + AddIssue(constructorDeclaration.NameToken, ctx.TranslateString("Convert public to protected"), script => + script.Replace(constructorDeclaration.ModifierTokens.First (t => t.Modifier == Modifiers.Public), new CSharpModifierToken(TextLocation.Empty, Modifiers.Protected))); } } } diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs new file mode 100644 index 0000000000..882899b3e8 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs @@ -0,0 +1,121 @@ +// +// ConvertToStaticMethodIssue.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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.Collections.Generic; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [IssueDescription("Make this method static", + Description = "This method doesn't use any non static members so it can be made static", + Severity = Severity.Hint, + IssueMarker = IssueMarker.Underline)] + public class ConvertToStaticMethodIssue : ICodeIssueProvider + { + public IEnumerable GetIssues(BaseRefactoringContext context) + { + return new GatherVisitor(context).GetIssues(); + } + + private class GatherVisitor : GatherVisitorBase + { + private bool initializerInvoked; + private ConstructorInitializer initializer; + + public GatherVisitor(BaseRefactoringContext context) + : base(context) { + } + + public override void VisitMethodDeclaration(MethodDeclaration declaration) + { + // TODO: Invert if without else + // ex. if (cond) DoSomething () == if (!cond) return; DoSomething () + // beware of loop contexts return should be continue then. + var context = ctx; + var methodDeclaration = declaration; + + var resolved = context.Resolve(methodDeclaration) as MemberResolveResult; + if (resolved == null) + return; + var isImplementingInterface = resolved.Member.ImplementedInterfaceMembers.Any(); + + if (isImplementingInterface) + return; + + AddIssue(methodDeclaration.NameToken.StartLocation, methodDeclaration.NameToken.EndLocation, + context.TranslateString(string.Format("Make '{0}' static", methodDeclaration.Name)), + script => ExecuteScriptToFixStaticMethodIssue(script, context, methodDeclaration)); + } + + private static void ExecuteScriptToFixStaticMethodIssue(Script script, + BaseRefactoringContext context, + AstNode methodDeclaration) + { + var clonedDeclaration = (MethodDeclaration) methodDeclaration.Clone(); + clonedDeclaration.Modifiers |= Modifiers.Static; + script.Replace(methodDeclaration, clonedDeclaration); + var rr = context.Resolve(methodDeclaration) as MemberResolveResult; + var method = (IMethod) rr.Member; + //method.ImplementedInterfaceMembers.Any(m => methodGroupResolveResult.Methods.Contains((IMethod)m)); + + script.DoGlobalOperationOn(rr.Member, + (fctx, fscript, fnode) => { DoStaticMethodGlobalOperation(fnode, fctx, rr, fscript); }); + } + + private static void DoStaticMethodGlobalOperation(AstNode fnode, RefactoringContext fctx, MemberResolveResult rr, + Script fscript) + { + if (fnode is MemberReferenceExpression) { + var memberReference = new MemberReferenceExpression + ( + new TypeReferenceExpression( + fctx.CreateShortType(rr.Member.DeclaringType)), + rr.Member.Name + ); + fscript.Replace(fnode, memberReference); + } + else { + var invoke = fnode as InvocationExpression; + if (invoke == null) return; + if ((invoke.Target is MemberReferenceExpression)) + return; + var memberReference = new MemberReferenceExpression + ( + new TypeReferenceExpression( + fctx.CreateShortType( + rr.Member.DeclaringType)), + rr.Member.Name + ); + fscript.Replace(invoke.Target, memberReference); + } + } + } + + } +} + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/DuplicateBodyMethodIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/DuplicateBodyMethodIssue.cs new file mode 100644 index 0000000000..7a108541e7 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/DuplicateBodyMethodIssue.cs @@ -0,0 +1,188 @@ +// +// DuplicateBodyMethodIssue.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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.Collections.Generic; +using System.Text; +using ICSharpCode.NRefactory.PatternMatching; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [IssueDescription("Methods have duplicate body", + Description = "One method has the same body as other method", + Severity = Severity.Hint, + IssueMarker = IssueMarker.Underline)] + public class DuplicateBodyMethodIssue : ICodeIssueProvider + { + #region ICodeIssueProvider implementation + + public IEnumerable GetIssues(BaseRefactoringContext context) + { + var visitor = new GatherVisitor(context); + visitor.GetMethods(); + visitor.ComputeConflicts(); + return visitor.GetIssues(); + } + + #endregion + + private class GatherVisitor : GatherVisitorBase + { + public List DeclaredMethods; + + public GatherVisitor(BaseRefactoringContext context) + : base(context) + { + DeclaredMethods = new List(); + } + + + static string GetMethodDescriptor(MethodDeclaration methodDeclaration) { + var sb = new StringBuilder(); + sb.Append(methodDeclaration.ReturnType); + sb.Append(";"); + foreach (var parameter in methodDeclaration.Parameters) { + sb.AppendFormat("{0}:{1};", parameter.Name, parameter.Type); + } + sb.Append(methodDeclaration.Modifiers); + return sb.ToString(); + } + + public void GetMethods() + { + ctx.RootNode.AcceptVisitor(this); + } + + internal void ComputeConflicts() + { + var dict = new Dictionary>(); + foreach (var declaredMethod in DeclaredMethods) + { + var methodDescriptor = GetMethodDescriptor(declaredMethod); + List listMethods; + if (!dict.TryGetValue(methodDescriptor, out listMethods)) + { + listMethods = new List(); + dict[methodDescriptor] = listMethods; + } + listMethods.Add(declaredMethod); + } + DeclaredMethods.Clear(); + + foreach (var list in dict.Values.Where(list => list.Count >= 2)) + { + for (var i = 0; i < list.Count - 1; i++) + { + var firstMethod = list[i]; + for (var j = i + 1; j < list.Count; j++) + { + var secondMethod = list[j]; + if (firstMethod.Body.IsMatch(secondMethod.Body)) + { + AddIssue(secondMethod.NameToken, + string.Format("Method '{0}' has the same with '{1}' ", secondMethod.Name, + firstMethod.Name), + script => { InvokeMethod(script, firstMethod, secondMethod); } + ); + } + } + } + } + } + + readonly InsertParenthesesVisitor _insertParenthesesVisitor = new InsertParenthesesVisitor(); + private TypeDeclaration _parentType; + + private void InvokeMethod(Script script, MethodDeclaration firstMethod, MethodDeclaration secondMethod) + { + var statement = + new ExpressionStatement(new InvocationExpression(new IdentifierExpression(firstMethod.Name), + firstMethod.Parameters.Select( + declaration => + GetArgumentExpression(declaration).Clone()))); + statement.AcceptVisitor(_insertParenthesesVisitor); + if(firstMethod.ReturnType.ToString()!="System.Void"){ + var returnStatement = new ReturnStatement(statement.Expression.Clone()); + + script.Replace(secondMethod.Body, new BlockStatement { returnStatement }); + } + else { + script.Replace(secondMethod.Body, new BlockStatement { statement }); + } + } + + static Expression GetArgumentExpression(ParameterDeclaration parameter) + { + var identifierExpr = new IdentifierExpression(parameter.Name); + switch (parameter.ParameterModifier) + { + case ParameterModifier.Out: + return new DirectionExpression(FieldDirection.Out, identifierExpr); + case ParameterModifier.Ref: + return new DirectionExpression(FieldDirection.Ref, identifierExpr); + } + return identifierExpr; + } + + public override void VisitMethodDeclaration(MethodDeclaration declaration) + { + var context = ctx; + var methodDeclaration = declaration; + + var resolved = context.Resolve(methodDeclaration) as MemberResolveResult; + if (resolved == null) + return; + var isImplementingInterface = resolved.Member.ImplementedInterfaceMembers.Any(); + + if (isImplementingInterface) + return; + if (declaration.Body.IsNull) + return; + + var parentType = declaration.Parent as TypeDeclaration; + if (parentType == null) + return; + if (_parentType == null) + _parentType = parentType; + else + { + //if we are here, it means that we switched from one class to another, so it means that we should compute + //the duplicates up-to now, then reset the list of methods + if (parentType != _parentType) + { + ComputeConflicts(); + DeclaredMethods.Add(declaration); + _parentType = parentType; + return; + } + } + + DeclaredMethods.Add(declaration); + } + } + } +} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionOfCompatibleTypeCastIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionOfCompatibleTypeCastIssue.cs index 3ecadf1e8f..4a3afffe23 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionOfCompatibleTypeCastIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionOfCompatibleTypeCastIssue.cs @@ -54,10 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring public override void VisitAssignmentExpression(AssignmentExpression assignmentExpression) { - base.VisitAssignmentExpression(assignmentExpression); - - VisitTypeCastExpression(assignmentExpression, ctx.Resolve(assignmentExpression.Left).Type, - ctx.Resolve(assignmentExpression.Right).Type); + var rightExpressionType = ctx.Resolve(assignmentExpression.Right).Type; + if (rightExpressionType.Kind == TypeKind.Class) + return; + var leftExpressionType = ctx.Resolve(assignmentExpression.Left).Type; + VisitTypeCastExpression(assignmentExpression, leftExpressionType, + rightExpressionType); } private AstType CreateShortType(AstNode node, IType fullType) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs index a7d0cb65aa..9bc34b073c 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeDemotedIssue.cs @@ -148,7 +148,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring TypeResolveCount += possibleTypes.Count; var validTypes = (from type in possibleTypes - where !tryResolve || TypeChangeResolvesCorrectly(parameter, rootResolutionNode, type) + where !tryResolve || TypeChangeResolvesCorrectly(ctx, parameter, rootResolutionNode, type) select type).ToList(); if (validTypes.Any()) { // don't demote an array to IList @@ -165,24 +165,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring internal int MembersWithIssues = 0; internal int MethodResolveCount = 0; - bool TypeChangeResolvesCorrectly(ParameterDeclaration parameter, AstNode rootNode, IType type) - { - MethodResolveCount++; - var resolver = ctx.GetResolverStateBefore(rootNode); - resolver = resolver.AddVariable(new DefaultParameter(type, parameter.Name)); - var astResolver = new CSharpAstResolver(resolver, rootNode, ctx.UnresolvedFile); - var validator = new TypeChangeValidationNavigator(); - astResolver.ApplyNavigator(validator, ctx.CancellationToken); - return !validator.FoundErrors; - } - IEnumerable GetActions(ParameterDeclaration parameter, IEnumerable possibleTypes) { var csResolver = ctx.Resolver.GetResolverStateBefore(parameter); var astBuilder = new TypeSystemAstBuilder(csResolver); foreach (var type in possibleTypes) { var localType = type; - var message = string.Format(ctx.TranslateString("Demote parameter to '{0}'"), type.FullName); + var message = String.Format(ctx.TranslateString("Demote parameter to '{0}'"), type.FullName); yield return new CodeAction(message, script => { script.Replace(parameter.Type, astBuilder.ConvertType(localType)); }, parameter.NameToken); @@ -190,7 +179,17 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring } } - class TypeChangeValidationNavigator : IResolveVisitorNavigator + public static bool TypeChangeResolvesCorrectly(BaseRefactoringContext ctx, ParameterDeclaration parameter, AstNode rootNode, IType type) + { + var resolver = ctx.GetResolverStateBefore(rootNode); + resolver = resolver.AddVariable(new DefaultParameter(type, parameter.Name)); + var astResolver = new CSharpAstResolver(resolver, rootNode, ctx.UnresolvedFile); + var validator = new TypeChangeValidationNavigator(); + astResolver.ApplyNavigator(validator, ctx.CancellationToken); + return !validator.FoundErrors; + } + + class TypeChangeValidationNavigator : IResolveVisitorNavigator { public bool FoundErrors { get; private set; } diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableIssue.cs new file mode 100644 index 0000000000..a8e4dd9ccc --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableIssue.cs @@ -0,0 +1,156 @@ +// +// ParameterCanBeIEnumerableIssue.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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.Collections.Generic; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + + [IssueDescription("A parameter can IEnumerable/ICollection/IList", + Description = "Finds parameters that can be demoted to a generic list.", + Category = IssueCategories.Opportunities, + Severity = Severity.Suggestion + )] + public class ParameterCanBeIEnumerableIssue : ICodeIssueProvider + { + readonly bool tryResolve; + + public ParameterCanBeIEnumerableIssue() : this (true) + { + } + + public ParameterCanBeIEnumerableIssue(bool tryResolve) + { + this.tryResolve = tryResolve; + } + + #region ICodeIssueProvider implementation + public IEnumerable GetIssues(BaseRefactoringContext context) + { + var gatherer = new GatherVisitor(context, tryResolve); + var issues = gatherer.GetIssues(); + return issues; + } + #endregion + + class GatherVisitor : GatherVisitorBase + { + bool tryResolve; + + public GatherVisitor(BaseRefactoringContext context, bool tryResolve) : base (context) + { + this.tryResolve = tryResolve; + } + + public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) + { + methodDeclaration.Attributes.AcceptVisitor(this); + if (HasEntryPointSignature(methodDeclaration)) + return; + var eligibleParameters = methodDeclaration.Parameters + .Where(p => p.ParameterModifier != ParameterModifier.Out && p.ParameterModifier != ParameterModifier.Ref) + .ToList(); + if (eligibleParameters.Count == 0) + return; + var declarationResolveResult = ctx.Resolve(methodDeclaration) as MemberResolveResult; + if (declarationResolveResult == null) + return; + var member = declarationResolveResult.Member; + if (member.IsOverride || member.IsOverridable || member.ImplementedInterfaceMembers.Any()) + return; + + var collector = new TypeCriteriaCollector(ctx); + methodDeclaration.AcceptVisitor(collector); + + foreach (var parameter in eligibleParameters) { + ProcessParameter(parameter, methodDeclaration.Body, collector); + } + } + + bool HasEntryPointSignature(MethodDeclaration methodDeclaration) + { + if (!methodDeclaration.Modifiers.HasFlag(Modifiers.Static)) + return false; + var returnType = ctx.Resolve(methodDeclaration.ReturnType).Type; + if (!returnType.IsKnownType(KnownTypeCode.Int32) && !returnType.IsKnownType(KnownTypeCode.Void)) + return false; + var parameterCount = methodDeclaration.Parameters.Count; + if (parameterCount == 0) + return true; + if (parameterCount != 1) + return false; + var parameterType = ctx.Resolve(methodDeclaration.Parameters.First()).Type as ArrayType; + return parameterType != null && parameterType.ElementType.IsKnownType(KnownTypeCode.String); + } + + void ProcessParameter(ParameterDeclaration parameter, AstNode rootResolutionNode, TypeCriteriaCollector collector) + { + var localResolveResult = ctx.Resolve(parameter) as LocalResolveResult; + if (localResolveResult == null) + return; + var variable = localResolveResult.Variable; + var typeKind = variable.Type.Kind; + if (!(typeKind == TypeKind.Class || + typeKind == TypeKind.Struct || + typeKind == TypeKind.Interface || + typeKind == TypeKind.Array) || + !collector.UsedVariables.Contains(variable)) + { + return; + } + + var candidateTypes = localResolveResult.Type.GetAllBaseTypes() + .Where(t => t.IsParameterized) + .ToList(); + + var validTypes = + (from type in candidateTypes + where !tryResolve || ParameterCanBeDemotedIssue.TypeChangeResolvesCorrectly(ctx, parameter, rootResolutionNode, type) + select type).ToList(); + if (!validTypes.Any()) return; + + var foundType = validTypes.FirstOrDefault(); + if (foundType == null) + return; + + AddIssue(parameter.NameToken, string.Format(ctx.TranslateString("Parameter can be {0}"), + foundType.Name), + script => script.Replace(parameter.Type, CreateShortType(ctx, foundType, parameter))); + } + + public static AstType CreateShortType(BaseRefactoringContext refactoringContext, IType expressionType, AstNode node) + { + + var csResolver = refactoringContext.Resolver.GetResolverStateBefore(node); + var builder = new TypeSystemAstBuilder(csResolver); + return builder.ConvertType(expressionType); + } + } + } +} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveFieldRefactoryActionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveFieldRefactoryActionTests.cs new file mode 100644 index 0000000000..3b2023a10c --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveFieldRefactoryActionTests.cs @@ -0,0 +1,96 @@ +// +// RemoveFieldRefactoryActionTests.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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 NUnit.Framework; + +namespace ICSharpCode.NRefactory.CSharp.CodeActions +{ + [TestFixture] + public class RemoveFieldRefactoryActionTests : ContextActionTestBase + { + [Test] + public void RemoveOneField() + { + Test( + @" +class A { + int $field; +} +", + @" +class A { +} +" + );} + + [Test] + public void RemoveOneFieldAndAssignmentValue() + { + Test( + @" +class A { + int $field; + A() { + field = 3; + } +} +", + @" +class A { + A() { + } +} +" + ); + } + + [Test] + public void RemoveOneFieldAndAssignmentValueAndMethodCall() + { + Test( + @" +class A { + int $field; + A() { + field = 3; +if(field!=0) + Method(field); + } +} +", + @" +class A { + A() { +if(TODO!=0) + Method(TODO); + } +} +" + ); + } + } +} + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs similarity index 57% rename from ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs rename to ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs index 2b8a224406..a32fa16d80 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs @@ -1,10 +1,10 @@ // -// ConvertToStaticMethodActionTests.cs +// ConvertToStaticMethodIssue.cs // // Author: -// Ciprian Khlud +// Ciprian Khlud // -// Copyright (c) 2013 Ciprian Khlud +// Copyright (c) 2013 Ciprian Khlud // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,50 +23,53 @@ // 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 ICSharpCode.NRefactory.CSharp.Refactoring; + using NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring; -namespace ICSharpCode.NRefactory.CSharp.CodeActions { - [TestFixture] - public class ConvertToStaticMethodActionTests : ContextActionTestBase - { - [Test] - public void Test() - { - Test( - @"class TestClass +namespace ICSharpCode.NRefactory.CSharp.CodeIssues +{ + [TestFixture] + public class ConvertToStaticMethodIssueTests : InspectionActionTestBase + { + + [Test] + public void Test() + { + Test( + @"class TestClass { void $Test () { int a = 2; } }", - @"class TestClass + @"class TestClass { static void Test () { int a = 2; } }" - ); - } - [Test] - public void TestWithVirtualFunction() { - - var input = @"class TestClass + ); + } + [Test] + public void TestWithVirtualFunction() { + + var input = @"class TestClass { public virtual void $Test () { int a = 2; } -}"; - TestWrongContext(input); - } - - [Test] - public void TestWithInterface() { - - var input = @"interface IBase { +}"; + TestWrongContext(input); + } + + [Test] + public void TestWithInterface() { + + var input = @"interface IBase { void Test(); } class TestClass : IBase @@ -76,20 +79,22 @@ class TestClass : IBase int a = 2; } }"; - TestWrongContext(input); - } - [Test] - public void TestWithStaticFunction() - { - - var input = @"class TestClass + TestWrongContext(input); + } + [Test] + public void TestWithStaticFunction() + { + + var input = @"class TestClass { static void $Test () { int a = 2; } }"; - TestWrongContext(input); - } - } -} \ No newline at end of file + TestWrongContext(input); + } + + } + +} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/DuplicateBodyMethodIssueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/DuplicateBodyMethodIssueTests.cs new file mode 100644 index 0000000000..d5283702bb --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/DuplicateBodyMethodIssueTests.cs @@ -0,0 +1,92 @@ +// +// DuplicateBodyMethodIssueTests.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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 NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring; + +namespace ICSharpCode.NRefactory.CSharp.CodeIssues +{ + + [TestFixture] + public class DuplicateBodyMethodIssueTests : InspectionActionTestBase + { + + [Test] + public void Test() + { + Test( + @"class TestClass { + void Test () + { + int a = 2; + } + void $Test2 () { + int a = 2; + } +}", + @"class TestClass { + void Test () + { + int a = 2; + } + void Test2 () { + Test (); + } +} +" + ); + } + [Test] + public void TestNonVoid() + { + Test( + @"class TestClass { + int Test () + { + int a = 2; + return a; + } + int $Test2 () { + int a = 2; + return a; + } +}", + @"class TestClass { + int Test () + { + int a = 2; + return a; + } + int Test2 () { + return Test (); + } +} +" + ); + } + } + +} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionOfCompatibleTypeCastIssueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionOfCompatibleTypeCastIssueTests.cs index dda08566be..dd6fb0d6de 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionOfCompatibleTypeCastIssueTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionOfCompatibleTypeCastIssueTests.cs @@ -44,20 +44,79 @@ class TestClass Base x; x = i; } +}"; + Test(input, 0); + } + + [Test] + public void TestConversionDoubleFloat() + { + var input = @" +class Foo +{ + void Bar () { + double c = 3.5; + float fc; + fc = c; + } }"; var output = @" -class Base {} -class Test: Base {} +class Foo +{ + void Bar (){ + double c = 3.5; + float fc; + fc = (float)c; + } +}"; + //TODO: + //Test is failing as conversion seems to have a bug that + //considers that double is implicit convertible to float, + //when should it be explicitly convertible to float + + //Test(input, output); + } + + [Test] + public void TestConversionEnumToInt() + { + var input = @" +class Foo +{ + enum Enum { Zero } + void Bar () { + var e = Enum.Zero; + int val; + val = e; + } +}"; + var output = @" +class Foo +{ + enum Enum { Zero } + void Bar () { + var e = Enum.Zero; + int val; + val = (Enum)e; + } +}"; + Test(input, output); + } + + [Test] + public void TestConversionSameType() + { + var input = @" class TestClass { - void TestMethod (Test i) + void TestMethod () { - Base x; - x = (Test)i; + int x =0; + int y = 1; + $x = i; } }"; - Test(input, output); + Test(input, 0); } - } } \ No newline at end of file diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs index f20d38102f..ecef790c70 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs @@ -95,6 +95,12 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues Assert.AreEqual (1, issues.Count); CheckFix (context, issues[0], output, fixIndex); } + + protected static void TestWrongContext (string input) + where T : ICodeIssueProvider, new () + { + Test(input, 0); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableTests.cs new file mode 100644 index 0000000000..2ad475e739 --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterCanBeDemotedIssue/ParameterCanBeIEnumerableTests.cs @@ -0,0 +1,98 @@ +// +// ParameterCanBeIEnumerableTests.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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 NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.CodeActions; +using ICSharpCode.NRefactory.CSharp.Refactoring; + +namespace ICSharpCode.NRefactory.CSharp.CodeIssues +{ + [TestFixture] + public class ParameterCanBeIEnumerableTests : InspectionActionTestBase + { + [Test] + public void CheckIEnumerable() + { + var input = @" +using System.Collections.Generic; +class TestClass +{ + void Write(string[] texts) + { + foreach(var item in texts) { } + } +}"; + TestRefactoringContext context; + var issues = GetIssues(new ParameterCanBeIEnumerableIssue(), input, out context); + Assert.AreEqual(1, issues.Count); + var issue = issues[0]; + // Suggested types: IList and IReadOnlyList + Assert.AreEqual(1, issue.Actions.Count); + + CheckFix(context, issues[0], @" +using System.Collections.Generic; +class TestClass +{ + void Write(IEnumerable texts) + { + foreach(var item in texts) { } + } +}"); + } + [Test] + public void CheckIList() + { + var input = @" +using System.Collections.Generic; +class TestClass +{ + void Write(List texts) + { + if(texts.Count == 0)return; + foreach(var item in texts) { } + } +}"; + TestRefactoringContext context; + var issues = GetIssues(new ParameterCanBeIEnumerableIssue(), input, out context); + Assert.AreEqual(1, issues.Count); + var issue = issues[0]; + // Suggested types: IList and IReadOnlyList + Assert.AreEqual(1, issue.Actions.Count); + + CheckFix(context, issues[0], @" +using System.Collections.Generic; +class TestClass +{ + void Write(ICollection texts) + { + if(texts.Count == 0)return; + foreach(var item in texts) { } + } +}"); + } + } +} diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index bdae167fa6..04902be570 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -1,4 +1,4 @@ - + {63D3B27A-D966-4902-90B3-30290E1692F1} @@ -109,7 +109,6 @@ - @@ -410,6 +409,9 @@ + + + @@ -432,17 +434,7 @@ False - - - - - - - - - - - + diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs index 2b419e5b7b..001aa14416 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs @@ -372,6 +372,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase public const int SOf = sizeof(float); public const int SOd = sizeof(double); public const int SObl = sizeof(bool); - public const int SOe = sizeof(MyEnum); + public static readonly unsafe int SOe = sizeof(MyEnum); } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index ef9cdfc217..c14a341a1a 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -1258,7 +1258,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } [Test] - public void ConstantFields() + public unsafe void ConstantFields() { ITypeDefinition type = GetTypeDefinition(typeof(ConstantFieldTest)); AssertConstantField(type, "Cb", 42); diff --git a/NRefactory.suo b/NRefactory.suo new file mode 100644 index 0000000000..cb425d4826 Binary files /dev/null and b/NRefactory.suo differ