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