diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
index 8990fb5d82..032aa64832 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
@@ -1,4 +1,4 @@
-// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
+// Copyright (c) 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
@@ -26,6 +26,7 @@ using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
+using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Analysis
{
@@ -750,5 +751,57 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return CreateConnectedEndNode(fixedStatement, bodyEnd);
}
}
+
+ ///
+ /// Debugging helper that exports a control flow graph.
+ ///
+ public static GraphVizGraph ExportGraph(IList nodes)
+ {
+ GraphVizGraph g = new GraphVizGraph();
+ GraphVizNode[] n = new GraphVizNode[nodes.Count];
+ Dictionary dict = new Dictionary();
+ for (int i = 0; i < n.Length; i++) {
+ dict.Add(nodes[i], i);
+ n[i] = new GraphVizNode(i);
+ string name = "#" + i + " = ";
+ switch (nodes[i].Type) {
+ case ControlFlowNodeType.StartNode:
+ case ControlFlowNodeType.BetweenStatements:
+ name += nodes[i].NextStatement.DebugToString();
+ break;
+ case ControlFlowNodeType.EndNode:
+ name += "End of " + nodes[i].PreviousStatement.DebugToString();
+ break;
+ case ControlFlowNodeType.LoopCondition:
+ name += "Condition in " + nodes[i].NextStatement.DebugToString();
+ break;
+ default:
+ name += "?";
+ break;
+ }
+ n[i].label = name;
+ g.AddNode(n[i]);
+ }
+ for (int i = 0; i < n.Length; i++) {
+ foreach (ControlFlowEdge edge in nodes[i].Outgoing) {
+ GraphVizEdge ge = new GraphVizEdge(i, dict[edge.To]);
+ if (edge.IsLeavingTryFinally)
+ ge.style = "dashed";
+ switch (edge.Type) {
+ case ControlFlowEdgeType.ConditionTrue:
+ ge.color = "green";
+ break;
+ case ControlFlowEdgeType.ConditionFalse:
+ ge.color = "red";
+ break;
+ case ControlFlowEdgeType.Jump:
+ ge.color = "blue";
+ break;
+ }
+ g.AddEdge(ge);
+ }
+ }
+ return g;
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
index ebb8d419d3..524966d7fb 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
@@ -78,6 +78,10 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
}
}
+ public IEnumerable ReachableStatements {
+ get { return reachableStatements; }
+ }
+
public bool IsReachable(Statement statement)
{
return reachableStatements.Contains(statement);
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
index 06c1f6e4b6..a9de1e7295 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
@@ -119,16 +119,20 @@ namespace ICSharpCode.NRefactory.CSharp
protected override void VisitChildren (AstNode node)
{
- if (!FormattingRegion.IsEmpty) {
- if (node.EndLocation < FormattingRegion.Begin || node.StartLocation > FormattingRegion.End)
- return;
- }
-
AstNode next;
for (var child = node.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue
// if the visitor removes/replaces child.
next = child.NextSibling;
+
+ if (!FormattingRegion.IsEmpty) {
+ if (child.EndLocation < FormattingRegion.Begin) {
+ continue;
+ }
+ if (child.StartLocation > FormattingRegion.End) {
+ break;
+ }
+ }
child.AcceptVisitor (this);
}
}
@@ -404,7 +408,8 @@ namespace ICSharpCode.NRefactory.CSharp
void ForceSpace(int startOffset, int endOffset, bool forceSpace)
{
int lastNonWs = SearchLastNonWsChar(startOffset, endOffset);
- AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : "");
+ if (lastNonWs >= 0)
+ AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : "");
}
// void ForceSpacesAfter (AstNode n, bool forceSpaces)
// {
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
index d0dde5fa32..8d788bbac9 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
@@ -301,6 +301,7 @@
+
@@ -316,11 +317,11 @@
+
-
@@ -333,7 +334,6 @@
-
@@ -536,4 +536,4 @@
-
+
\ No newline at end of file
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
index c7e0c68779..8155ffe459 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
@@ -122,6 +122,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
return resolver.GetConversion(expression, cancellationToken);
}
+
+ public TypeSystemAstBuilder CreateTypeSytemAstBuilder(AstNode node)
+ {
+ var csResolver = resolver.GetResolverStateBefore(node);
+ return new TypeSystemAstBuilder(csResolver);
+ }
#endregion
#region Code Analyzation
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs
index 3e5049a9fd..a29a9f62c5 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs
@@ -70,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var blockStatement = new BlockStatement();
blockStatement.Statements.Add(iterator);
script.Replace(usingStatement.EmbeddedStatement, blockStatement);
- script.FormatText(blockStatement);
+ script.FormatText((AstNode)blockStatement);
} else if (usingStatement.EmbeddedStatement is BlockStatement) {
var anchorNode = usingStatement.EmbeddedStatement.FirstChild;
script.InsertAfter(anchorNode, iterator);
@@ -149,11 +149,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
IType collectionType = null;
foreach (var baseType in type.GetAllBaseTypes()) {
- var baseTypeDefinition = baseType.GetDefinition();
- if (baseTypeDefinition.IsKnownType(KnownTypeCode.IEnumerableOfT)) {
+ if (baseType.IsKnownType(KnownTypeCode.IEnumerableOfT)) {
collectionType = baseType;
break;
- } else if (baseTypeDefinition.IsKnownType(KnownTypeCode.IEnumerable)) {
+ } else if (baseType.IsKnownType(KnownTypeCode.IEnumerable)) {
collectionType = baseType;
// Don't break, continue in case type implements IEnumerable
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
index 7ff3a99360..9691ae63e6 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
@@ -115,8 +115,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} else if (parent is OperatorDeclaration) {
body = ((OperatorDeclaration)parent).Body;
}
- if (body != null)
- CheckVariable (((LocalResolveResult)ctx.Resolve (parameterDeclaration)).Variable, body);
+ if (body != null) {
+ var lrr = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
+ if (lrr != null)
+ CheckVariable (lrr.Variable, body);
+ }
base.VisitParameterDeclaration (parameterDeclaration);
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs
index 7437e74f1c..055518a24c 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs
@@ -56,6 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
base.VisitAssignmentExpression (assignmentExpression);
+ if (assignmentExpression.Operator != AssignmentOperatorType.Assign)
+ return;
if (!(assignmentExpression.Left is IdentifierExpression) &&
!(assignmentExpression.Left is MemberReferenceExpression))
return;
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CastExpressionOfIncompatibleTypeIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CastExpressionOfIncompatibleTypeIssue.cs
index 0cd039c107..c81d39693a 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CastExpressionOfIncompatibleTypeIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CastExpressionOfIncompatibleTypeIssue.cs
@@ -71,6 +71,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void VisitTypeCastExpression (Expression expression, IType exprType, IType castToType)
{
+ if (exprType.Kind == TypeKind.Unknown || castToType.Kind == TypeKind.Unknown)
+ return;
var foundConversion = conversion.ExplicitConversion(exprType, castToType);
if (foundConversion == Conversion.None)
AddIssue (expression, ctx.TranslateString ("Type cast expression of incompatible type"));
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs
index 08103da6fb..4c67c2ee9f 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs
@@ -80,12 +80,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
void AddIsNaNIssue(BinaryOperatorExpression binaryOperatorExpr, Expression argExpr, string floatType)
{
- if (ctx.Resolve (argExpr).Type.ReflectionName != "System.Single")
+ if (!ctx.Resolve(argExpr).Type.IsKnownType(KnownTypeCode.Single))
floatType = "double";
- AddIssue (binaryOperatorExpr, string.Format(ctx.TranslateString ("Use {0}.IsNan()"), floatType),
+ AddIssue(binaryOperatorExpr, string.Format(ctx.TranslateString ("Use {0}.IsNaN()"), floatType),
script => {
- Expression expr = new InvocationExpression (new MemberReferenceExpression (
- new TypeReferenceExpression (new PrimitiveType (floatType)), "IsNaN"), argExpr.Clone ());
+ Expression expr = new PrimitiveType(floatType).Invoke("IsNaN", argExpr.Clone());
if (binaryOperatorExpr.Operator == BinaryOperatorType.InEquality)
expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr);
script.Replace (binaryOperatorExpr, expr);
@@ -109,13 +108,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
AddIssue (binaryOperatorExpression, ctx.TranslateString ("Compare a difference with EPSILON"),
script => {
// Math.Abs(diff) op EPSILON
+ var builder = ctx.CreateTypeSytemAstBuilder(binaryOperatorExpression);
var diff = new BinaryOperatorExpression (binaryOperatorExpression.Left.Clone (),
BinaryOperatorType.Subtract, binaryOperatorExpression.Right.Clone ());
- var abs = new InvocationExpression (
- new MemberReferenceExpression (
- new TypeReferenceExpression (new SimpleType ("System.Math")),
- "Abs"),
- diff);
+ var abs = builder.ConvertType(new TopLevelTypeName("System", "Math")).Invoke("Abs", diff);
var op = binaryOperatorExpression.Operator == BinaryOperatorType.Equality ?
BinaryOperatorType.LessThan : BinaryOperatorType.GreaterThan;
var epsilon = new IdentifierExpression ("EPSILON");
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs
index e5eb242e76..4fbe64f46e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs
@@ -27,6 +27,7 @@
using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -44,11 +45,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- static CSharpConversions conversion;
+ readonly CSharpConversions conversions;
public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
- conversion = new CSharpConversions(ctx.Compilation);
+ conversions = CSharpConversions.Get(ctx.Compilation);
}
public override void VisitIsExpression (IsExpression isExpression)
@@ -58,8 +59,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var type = ctx.Resolve (isExpression.Expression).Type;
var providedType = ctx.ResolveType (isExpression.Type);
- var foundConversion = conversion.ImplicitConversion(type, providedType);
- if (foundConversion == Conversion.None)
+ var foundConversion = conversions.ImplicitConversion(type, providedType);
+ if (!IsValidReferenceOrBoxingConversion(type, providedType))
return;
var action = new CodeAction (ctx.TranslateString ("Compare with 'null'"),
@@ -68,6 +69,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
AddIssue (isExpression, ctx.TranslateString ("Given expression is always of the provided type. " +
"Consider comparing with 'null' instead"), new [] { action });
}
+
+ bool IsValidReferenceOrBoxingConversion(IType fromType, IType toType)
+ {
+ Conversion c = conversions.ImplicitConversion(fromType, toType);
+ return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion);
+ }
}
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs
index 7c28f3d1f9..543b2bdb61 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs
@@ -25,6 +25,10 @@
// THE SOFTWARE.
using System.Collections.Generic;
+using System.Linq;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -42,21 +46,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
+ readonly CSharpConversions conversions;
public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx)
{
+ conversions = CSharpConversions.Get(ctx.Compilation);
}
public override void VisitIsExpression (IsExpression isExpression)
{
base.VisitIsExpression (isExpression);
+ var conversions = CSharpConversions.Get(ctx.Compilation);
var exprType = ctx.Resolve (isExpression.Expression).Type;
var providedType = ctx.ResolveType (isExpression.Type);
- if (TypeCompatibilityHelper.CheckTypeCompatibility(exprType, providedType) ==
- TypeCompatibilityHelper.TypeCompatiblity.NeverOfProvidedType)
- AddIssue (isExpression, ctx.TranslateString ("Given expression is never of the provided type"));
+ if (exprType.Kind == TypeKind.Unknown || providedType.Kind == TypeKind.Unknown)
+ return;
+ if (IsValidReferenceOrBoxingConversion(exprType, providedType))
+ return;
+
+ var exprTP = exprType as ITypeParameter;
+ var providedTP = providedType as ITypeParameter;
+ if (exprTP != null) {
+ if (IsValidReferenceOrBoxingConversion(exprTP.EffectiveBaseClass, providedType)
+ && exprTP.EffectiveInterfaceSet.All(i => IsValidReferenceOrBoxingConversion(i, providedType)))
+ return;
+ }
+ if (providedTP != null) {
+ if (IsValidReferenceOrBoxingConversion(exprType, providedTP.EffectiveBaseClass))
+ return;
+ }
+
+ AddIssue (isExpression, ctx.TranslateString ("Given expression is never of the provided type"));
+ }
+
+ bool IsValidReferenceOrBoxingConversion(IType fromType, IType toType)
+ {
+ Conversion c = conversions.ExplicitConversion(fromType, toType);
+ return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion || c.IsUnboxingConversion);
}
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
index dc7ab72d0f..73e5051f52 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
@@ -63,8 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
var firstParam = parameters.FirstOrNullObject() as PrimitiveExpression;
var secondParam = parameters.LastOrNullObject() as PrimitiveExpression;
- if (firstParam == null || firstParam.Value.GetType() != typeof(string) ||
- secondParam == null || firstParam.Value.GetType() != typeof(string))
+ if (firstParam == null || !(firstParam.Value is string) ||
+ secondParam == null || !(secondParam.Value is string))
return;
var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
if (type == null)
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs
index 68ae2e8529..44c08d3299 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs
@@ -43,8 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
- readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
-
public GatherVisitor(BaseRefactoringContext ctx)
: base (ctx)
{
@@ -58,30 +56,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (methodDeclaration.Body.IsNull)
return;
- var cfg = cfgBuilder.BuildControlFlowGraph (methodDeclaration.Body, ctx.Resolver,
- ctx.CancellationToken);
- var stack = new Stack ();
- var visitedNodes = new HashSet ();
- stack.Push (cfg [0]);
- while (stack.Count > 0) {
- var node = stack.Pop ();
-
- // reach method's end
- if (node.PreviousStatement == methodDeclaration.Body)
- return;
- // reach a return statement
- if (node.NextStatement is ReturnStatement ||
- node.NextStatement is ThrowStatement)
- return;
-
- foreach (var edge in node.Outgoing) {
- if (visitedNodes.Add(edge.To))
- stack.Push(edge.To);
+ var reachability = ctx.CreateReachabilityAnalysis(methodDeclaration.Body);
+ bool hasReachableReturn = false;
+ foreach (var statement in reachability.ReachableStatements) {
+ if (statement is ReturnStatement || statement is ThrowStatement || statement is YieldBreakStatement) {
+ hasReachableReturn = true;
+ break;
}
}
-
- AddIssue (methodDeclaration.NameToken,
- ctx.TranslateString ("Method never reaches its end or a 'return' statement."));
+ if (!hasReachableReturn && !reachability.IsEndpointReachable(methodDeclaration.Body)) {
+ AddIssue (methodDeclaration.NameToken,
+ ctx.TranslateString ("Method never reaches its end or a 'return' statement."));
+ }
}
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodOverloadHidesOptionalParameterIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodOverloadHidesOptionalParameterIssue.cs
index 3420a3ddc2..2911cee187 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodOverloadHidesOptionalParameterIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodOverloadHidesOptionalParameterIssue.cs
@@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (method.Parameters.Count == 0 || !method.Parameters.Last ().IsOptional)
return;
- var overloads = method.DeclaringType.GetMembers (m => m.Name == method.Name).OfType ()
+ var overloads = method.DeclaringType.GetMethods(m => m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count)
.ToArray ();
var parameterNodes = methodDeclaration.Parameters.ToArray();
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MissingStringComparisonIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MissingStringComparisonIssue.cs
new file mode 100644
index 0000000000..b037f8e2d1
--- /dev/null
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MissingStringComparisonIssue.cs
@@ -0,0 +1,106 @@
+//
+// MissingStringComparisonIssue.cs
+//
+// Author:
+// Daniel Grunwald
+//
+// Copyright (c) 2012 Daniel Grunwald
+//
+// 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 System.Linq;
+using ICSharpCode.NRefactory.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.NRefactory.TypeSystem.Implementation;
+
+namespace ICSharpCode.NRefactory.CSharp.Refactoring
+{
+ [IssueDescription("Missing StringComparison argument",
+ Description = "Warns when a culture-aware comparison is used by default.",
+ Category = IssueCategories.CodeQualityIssues,
+ Severity = Severity.Warning)]
+ public class MissingStringComparisonIssue : ICodeIssueProvider
+ {
+ public IEnumerable GetIssues(BaseRefactoringContext context)
+ {
+ return new GatherVisitor(context).GetIssues();
+ }
+
+ class GatherVisitor : GatherVisitorBase
+ {
+ public GatherVisitor(BaseRefactoringContext ctx) : base(ctx)
+ {
+ }
+
+ public override void VisitInvocationExpression(InvocationExpression invocationExpression)
+ {
+ base.VisitInvocationExpression(invocationExpression);
+
+ MemberReferenceExpression mre = invocationExpression.Target as MemberReferenceExpression;
+ if (mre == null)
+ return;
+ switch (mre.MemberName) {
+ case "StartsWith":
+ case "EndsWith":
+ if (invocationExpression.Arguments.Count != 1)
+ return;
+ break;
+ case "IndexOf":
+ case "LastIndexOf":
+ break;
+ default:
+ return;
+ }
+
+ var rr = ctx.Resolve(invocationExpression) as InvocationResolveResult;
+ if (rr == null || rr.IsError) {
+ // Not an invocation resolve result - e.g. could be a UnknownMemberResolveResult instead
+ return;
+ }
+ if (!(rr.Member.DeclaringTypeDefinition != null && rr.Member.DeclaringTypeDefinition.KnownTypeCode == KnownTypeCode.String)) {
+ // Not a string operation
+ return;
+ }
+ IParameter firstParameter = rr.Member.Parameters.FirstOrDefault();
+ if (firstParameter == null || !firstParameter.Type.IsKnownType(KnownTypeCode.String))
+ return; // First parameter not a string
+ IParameter lastParameter = rr.Member.Parameters.Last();
+ if (lastParameter.Type.Name == "StringComparison")
+ return; // already specifying a string comparison
+ AddIssue(invocationExpression.LParToken.StartLocation, invocationExpression.RParToken.EndLocation,
+ mre.MemberName + "() call is missing StringComparison argument",
+ new [] {
+ new CodeAction("Use ordinal comparison", script => AddArgument(script, invocationExpression, "Ordinal")),
+ new CodeAction("Use culture-aware comparison", script => AddArgument(script, invocationExpression, "CurrentCulture")),
+ });
+ }
+
+ void AddArgument(Script script, InvocationExpression invocationExpression, string stringComparison)
+ {
+ var astBuilder = ctx.CreateTypeSytemAstBuilder(invocationExpression);
+ var newArgument = astBuilder.ConvertType(new TopLevelTypeName("System", "StringComparison")).Member(stringComparison);
+ var copy = (InvocationExpression)invocationExpression.Clone();
+ copy.Arguments.Add(newArgument);
+ script.Replace(invocationExpression, copy);
+ }
+ }
+ }
+}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs
index 45c930748f..3b255c029d 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs
@@ -6,7 +6,7 @@ using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
- [IssueDescription("Any() should be used with predicate and Where() removed",
+ [IssueDescription("Any()/First()/etc. should be used with predicate and Where() removed",
Description= "Detects redundant Where() with predicate calls followed by Any().",
Category = IssueCategories.CodeQualityIssues,
Severity = Severity.Hint)]
@@ -15,11 +15,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
static readonly AstNode pattern =
new InvocationExpression (
new MemberReferenceExpression (
- new NamedNode ("whereInvoke",
- new InvocationExpression (
- new MemberReferenceExpression (new AnyNode ("target"), "Where"),
- new AnyNode ())),
- "Any"));
+ new NamedNode ("whereInvoke",
+ new InvocationExpression (
+ new MemberReferenceExpression (new AnyNode ("target"), "Where"),
+ new AnyNode ())),
+ Pattern.AnyString));
public IEnumerable GetIssues(BaseRefactoringContext context)
{
@@ -41,11 +41,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
var anyResolve = ctx.Resolve (anyInvoke) as InvocationResolveResult;
- if (anyResolve == null || anyResolve.Member.FullName != "System.Linq.Enumerable.Any")
+ if (anyResolve == null || !HasPredicateVersion(anyResolve.Member))
return;
var whereInvoke = match.Get ("whereInvoke").Single ();
var whereResolve = ctx.Resolve (whereInvoke) as InvocationResolveResult;
- if (whereResolve == null || whereResolve.Member.FullName != "System.Linq.Enumerable.Where")
+ if (whereResolve == null || whereResolve.Member.Name != "Where" || !IsQueryExtensionClass(whereResolve.Member.DeclaringTypeDefinition))
return;
if (whereResolve.Member.Parameters.Count != 2)
return;
@@ -53,11 +53,47 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (predResolve.Type.TypeParameterCount != 2)
return;
- AddIssue (anyInvoke, "Redundant Where() call with predicate followed by Any()", script => {
- var arg = whereInvoke.Arguments.Single ().Clone ();
- var target = match.Get ("target").Single ().Clone ();
- script.Replace (anyInvoke, new InvocationExpression (new MemberReferenceExpression (target, "Any"), arg));
- });
+ AddIssue (
+ anyInvoke, string.Format("Redundant Where() call with predicate followed by {0}()", anyResolve.Member.Name),
+ script => {
+ var arg = whereInvoke.Arguments.Single ().Clone ();
+ var target = match.Get ("target").Single ().Clone ();
+ script.Replace (anyInvoke, new InvocationExpression (new MemberReferenceExpression (target, anyResolve.Member.Name), arg));
+ });
+ }
+
+ bool IsQueryExtensionClass(ITypeDefinition typeDef)
+ {
+ if (typeDef == null || typeDef.Namespace != "System.Linq")
+ return false;
+ switch (typeDef.Name) {
+ case "Enumerable":
+ case "ParallelEnumerable":
+ case "Queryable":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool HasPredicateVersion(IParameterizedMember member)
+ {
+ if (!IsQueryExtensionClass(member.DeclaringTypeDefinition))
+ return false;
+ switch (member.Name) {
+ case "Any":
+ case "Count":
+ case "First":
+ case "FirstOrDefault":
+ case "Last":
+ case "LastOrDefault":
+ case "LongCount":
+ case "Single":
+ case "SingleOrDefault":
+ return true;
+ default:
+ return false;
+ }
}
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs
index d050067f58..5342de7b4d 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs
@@ -89,6 +89,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
if (typeResolveResult.Type.Equals(member.DeclaringType))
return;
+ // check whether member.DeclaringType contains the original type
+ // (curiously recurring template pattern)
+ var v = new ContainsTypeVisitor(typeResolveResult.Type.GetDefinition());
+ member.DeclaringType.AcceptVisitor(v);
+ if (v.IsContained)
+ return;
AddIssue(issueAnchor, context.TranslateString("Static method invoked via derived type"),
GetActions(context, targetExpression, member));
}
@@ -96,14 +102,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IEnumerable GetActions(BaseRefactoringContext context, Expression targetExpression,
IMember member)
{
- var csResolver = context.Resolver.GetResolverStateBefore(targetExpression);
- var builder = new TypeSystemAstBuilder(csResolver);
+ var builder = context.CreateTypeSytemAstBuilder(targetExpression);
var newType = builder.ConvertType(member.DeclaringType);
string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText());
yield return new CodeAction(description, script => {
script.Replace(targetExpression, newType);
});
}
+
+ sealed class ContainsTypeVisitor : TypeVisitor
+ {
+ readonly ITypeDefinition searchedType;
+ internal bool IsContained;
+
+ public ContainsTypeVisitor(ITypeDefinition searchedType)
+ {
+ this.searchedType = searchedType;
+ }
+
+ public override IType VisitTypeDefinition(ITypeDefinition type)
+ {
+ if (type.Equals(searchedType))
+ IsContained = true;
+ return base.VisitTypeDefinition(type);
+ }
+ }
}
#endregion
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs
new file mode 100644
index 0000000000..d4a40e3f2b
--- /dev/null
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs
@@ -0,0 +1,58 @@
+// Copyright (c) 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.Semantics;
+using ICSharpCode.NRefactory.TypeSystem;
+
+namespace ICSharpCode.NRefactory.CSharp.Refactoring
+{
+ [IssueDescription("Result of async call is ignored",
+ Description = "Warns when the task returned by an async call is ignored, which causes exceptions" +
+ " thrown by the call to be silently ignored.",
+ Category = IssueCategories.CodeQualityIssues,
+ Severity = Severity.Warning)]
+ public class ResultOfAsyncCallShouldNotBeIgnoredIssue : ICodeIssueProvider
+ {
+ public IEnumerable GetIssues(BaseRefactoringContext context)
+ {
+ return new GatherVisitor(context).GetIssues();
+ }
+
+ sealed class GatherVisitor : GatherVisitorBase
+ {
+ public GatherVisitor(BaseRefactoringContext ctx)
+ : base(ctx)
+ {
+ }
+
+ public override void VisitExpressionStatement(ExpressionStatement expressionStatement)
+ {
+ base.VisitExpressionStatement(expressionStatement);
+ var invocation = expressionStatement.Expression as InvocationExpression;
+ if (invocation == null)
+ return;
+ var rr = ctx.Resolve(invocation) as InvocationResolveResult;
+ if (rr != null && (rr.Type.IsKnownType(KnownTypeCode.Task) || rr.Type.IsKnownType(KnownTypeCode.TaskOfT))) {
+ AddIssue(invocation, "Exceptions in async call will be silently ignored because the returned task is unused");
+ }
+ }
+ }
+ }
+}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
index a3cc5237a2..12016f7907 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
@@ -31,7 +31,7 @@ using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
///
- /// Checks for str == null && str == ""
+ /// Checks for str == null && str == " "
/// Converts to: string.IsNullOrEmpty (str)
///
[IssueDescription("Use string.IsNullOrEmpty",
@@ -124,6 +124,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (m.Success) {
var str = m.Get("str").Single();
+ var def = ctx.Resolve (str).Type.GetDefinition ();
+ if (def == null || def.KnownTypeCode != ICSharpCode.NRefactory.TypeSystem.KnownTypeCode.String)
+ return;
AddIssue(binaryOperatorExpression, ctx.TranslateString("Use string.IsNullOrEmpty"), script => {
Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone());
if (isNegated)
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
index 8d0412c412..489f29b5f8 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
@@ -62,8 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
{
var addAccessor = eventDeclaration.AddAccessor;
- FindIssuesInNode(addAccessor, addAccessor.Body, "add accessor");
var removeAccessor = eventDeclaration.RemoveAccessor;
+ // don't warn on empty custom events
+ if (addAccessor.Body.Statements.Count == 0 && removeAccessor.Body.Statements.Count == 0)
+ return;
+ FindIssuesInNode(addAccessor, addAccessor.Body, "add accessor");
FindIssuesInNode(removeAccessor, removeAccessor.Body, "remove accessor");
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
index cb9a51d76d..adf2b0cc69 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
@@ -28,6 +28,8 @@ using ICSharpCode.NRefactory.Semantics;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using System.Collections.Generic;
+using ICSharpCode.NRefactory.CSharp.Resolver;
+using System;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -41,15 +43,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
#region ICodeIssueProvider implementation
public IEnumerable GetIssues(BaseRefactoringContext context)
{
- return new GatherVisitor (context).GetIssues ();
+ var delegateVisitor = new GetDelgateUsagesVisitor (context);
+ context.RootNode.AcceptVisitor (delegateVisitor);
+
+ return new GatherVisitor (context, delegateVisitor).GetIssues ();
}
#endregion
+ // Collect all methods that are used as delegate
+ class GetDelgateUsagesVisitor : DepthFirstAstVisitor
+ {
+ BaseRefactoringContext ctx;
+ public readonly List UsedMethods = new List ();
+
+ public GetDelgateUsagesVisitor(BaseRefactoringContext ctx)
+ {
+ this.ctx = ctx;
+ }
+
+ public override void VisitIdentifierExpression(IdentifierExpression identifierExpression)
+ {
+ var mgr = ctx.Resolve (identifierExpression) as MethodGroupResolveResult;
+ if (mgr != null)
+ UsedMethods.AddRange (mgr.Methods);
+ base.VisitIdentifierExpression(identifierExpression);
+ }
+
+ public override void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
+ {
+ var mgr = ctx.Resolve (memberReferenceExpression) as MethodGroupResolveResult;
+ if (mgr != null)
+ UsedMethods.AddRange (mgr.Methods);
+ base.VisitMemberReferenceExpression(memberReferenceExpression);
+ }
+ }
+
class GatherVisitor : GatherVisitorBase
{
- public GatherVisitor (BaseRefactoringContext ctx)
+ GetDelgateUsagesVisitor usedDelegates;
+ public GatherVisitor (BaseRefactoringContext ctx, GetDelgateUsagesVisitor usedDelegates)
: base (ctx)
{
+ this.usedDelegates = usedDelegates;
}
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
@@ -66,13 +101,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
if (member.ImplementedInterfaceMembers.Any ())
return;
-
- base.VisitMethodDeclaration(methodDeclaration);
+ if (usedDelegates.UsedMethods.Any (m => m.Region.Begin == methodDeclaration.StartLocation))
+ return;
+ foreach (var parameter in methodDeclaration.Parameters)
+ parameter.AcceptVisitor (this);
}
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)
{
- base.VisitParameterDeclaration (parameterDeclaration);
+ base.VisitParameterDeclaration (parameterDeclaration);
if (!(parameterDeclaration.Parent is MethodDeclaration))
return;
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
deleted file mode 100644
index d30d245654..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// LocalVariableOnlyAssignedIssue.cs
-//
-// Author:
-// Mansheng Yang
-//
-// Copyright (c) 2012 Mansheng Yang
-//
-// 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 ICSharpCode.NRefactory.Semantics;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
-
- [IssueDescription ("Local variable is only assigned",
- Description = "Local variable is assigned by its value is never used",
- Category = IssueCategories.CodeQualityIssues,
- Severity = Severity.Warning,
- IssueMarker = IssueMarker.Underline)]
- public class LocalVariableOnlyAssignedIssue : VariableOnlyAssignedIssue
- {
- internal override GatherVisitorBase GetGatherVisitor (BaseRefactoringContext ctx)
- {
- return new GatherVisitor (ctx);
- }
-
- class GatherVisitor : GatherVisitorBase
- {
- public GatherVisitor (BaseRefactoringContext ctx)
- : base (ctx)
- {
- }
-
- public override void VisitVariableInitializer (VariableInitializer variableInitializer)
- {
- base.VisitVariableInitializer (variableInitializer);
-
- var decl = variableInitializer.Parent as VariableDeclarationStatement;
- if (decl == null)
- return;
-
- var resolveResult = ctx.Resolve (variableInitializer) as LocalResolveResult;
- if (resolveResult == null)
- return;
- if (!TestOnlyAssigned (ctx, decl.Parent, resolveResult.Variable))
- return;
- AddIssue (variableInitializer.NameToken,
- ctx.TranslateString ("Local variable is assigned by its value is never used"));
- }
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
index 0d5ab0c8da..f3797fef4e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
@@ -28,7 +28,7 @@ using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[IssueDescription ("Parameter is only assigned",
- Description = "Parameter is assigned by its value is never used.",
+ Description = "Parameter is assigned but its value is never used.",
Category = IssueCategories.CodeQualityIssues,
Severity = Severity.Warning,
IssueMarker = IssueMarker.Underline)]
@@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return;
}
AddIssue(parameterDeclaration.NameToken,
- ctx.TranslateString("Parameter is assigned by its value is never used"));
+ ctx.TranslateString("Parameter is assigned but its value is never used"));
}
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
index 6c6d6820c2..126b59da0c 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
@@ -66,11 +66,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostDecrement:
assignment = true;
+ if (!(parent.Parent is ExpressionStatement))
+ nonAssignment = true;
continue;
}
} else if (parent is DirectionExpression) {
if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) {
assignment = true;
+ // Using dummy variables is necessary for ignoring
+ // out-arguments, so we don't want to warn for those.
+ nonAssignment = true;
continue;
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs
index f472880a68..7e4e9e0b36 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs
@@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Linq;
using System.Diagnostics;
using ICSharpCode.NRefactory.Editor;
+using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
@@ -95,13 +97,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return originalDocument.Version.MoveOffsetTo(currentDocument.Version, originalDocumentOffset);
}
- public override void FormatText(AstNode node)
+ public override void FormatText(IEnumerable nodes)
{
- var segment = GetSegment(node);
var syntaxTree = SyntaxTree.Parse(currentDocument, "dummy.cs");
- var formatter = new AstFormattingVisitor(FormattingOptions, currentDocument, Options);
- syntaxTree.AcceptVisitor(formatter);
- formatter.ApplyChanges(segment.Offset, segment.Length);
+ foreach (var node in nodes.OrderByDescending (n => n.StartLocation)) {
+ var segment = GetSegment(node);
+ var formatter = new AstFormattingVisitor(FormattingOptions, currentDocument, Options);
+
+ formatter.FormattingRegion = new ICSharpCode.NRefactory.TypeSystem.DomRegion (
+ currentDocument.GetLocation (segment.Offset),
+ currentDocument.GetLocation (segment.EndOffset)
+ );
+ syntaxTree.AcceptVisitor(formatter);
+ formatter.ApplyChanges(segment.Offset, segment.Length);
+ }
}
protected override int GetIndentLevelAt(int offset)
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
index 51897bf50e..75d92c1c7e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
@@ -202,21 +202,28 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
CorrectFormatting (node, node);
}
+ List nodesToFormat = new List ();
+
void CorrectFormatting(AstNode node, AstNode newNode)
{
if (node is Identifier || node is IdentifierExpression || node is CSharpTokenNode || node is AstType)
return;
if (node == null || node.Parent is BlockStatement) {
- FormatText(newNode);
+ nodesToFormat.Add (newNode);
} else {
- FormatText((node.Parent != null && (node.Parent is Statement || node.Parent is Expression || node.Parent is VariableInitializer)) ? node.Parent : newNode);
+ nodesToFormat.Add ((node.Parent != null && (node.Parent is Statement || node.Parent is Expression || node.Parent is VariableInitializer)) ? node.Parent : newNode);
}
}
public abstract void Remove (AstNode node, bool removeEmptyLine = true);
- public abstract void FormatText (AstNode node);
-
+ public abstract void FormatText (IEnumerable nodes);
+
+ public void FormatText (params AstNode[] node)
+ {
+ FormatText ((IEnumerable)node);
+ }
+
public virtual void Select (AstNode node)
{
// default implementation: do nothing
@@ -380,6 +387,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public virtual void Dispose()
{
+ FormatText (nodesToFormat);
}
public enum NewTypeContext {
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs
deleted file mode 100644
index 98ae4e36fb..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-//
-// TypeCompatibilityHelper.cs
-//
-// Author:
-// Mansheng Yang
-//
-// Copyright (c) 2012 Mansheng Yang
-//
-// 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.Linq;
-using ICSharpCode.NRefactory.TypeSystem;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- class TypeCompatibilityHelper
- {
- public enum TypeCompatiblity
- {
- MayOfProvidedType,
- AlwaysOfProvidedType,
- NeverOfProvidedType
- }
-
- static bool CheckTypeParameterConstraints (IType type, IEnumerable baseTypes,
- ITypeParameter typeParameter)
- {
- if (!typeParameter.DirectBaseTypes.All (t => baseTypes.Any (t2 => t2.Equals (t))))
- return false;
- if (typeParameter.HasDefaultConstructorConstraint &&
- !type.GetConstructors (c => c.IsPublic && c.Parameters.Count == 0).Any ())
- return false;
- return true;
- }
-
- public static TypeCompatiblity CheckTypeCompatibility(IType exprType, IType providedType)
- {
- var exprBaseTypes = exprType.GetAllBaseTypes ().ToArray ();
-
- // providedType is a base type of exprType
- if (exprBaseTypes.Any (t => t.Equals (providedType)))
- return TypeCompatiblity.AlwaysOfProvidedType;
-
- if ((exprType.IsReferenceType == true && providedType.IsReferenceType == false) ||
- (exprType.IsReferenceType == false && providedType.IsReferenceType == true))
- return TypeCompatiblity.NeverOfProvidedType;
-
- var typeParameter = exprType as ITypeParameter;
- var providedTypeParameter = providedType as ITypeParameter;
-
- if (typeParameter != null) {
- // check if providedType can be a derived type
- var providedBaseTypes = providedType.GetAllBaseTypes ().ToArray ();
- var providedTypeDef = providedType.GetDefinition ();
- // if providedType is sealed, check if it fullfills all the type parameter constraints,
- // otherwise, only check if it is derived from EffectiveBaseClass
- if (providedTypeParameter == null && (providedTypeDef == null || providedTypeDef.IsSealed)) {
- if (CheckTypeParameterConstraints (providedType, providedBaseTypes, typeParameter))
- return TypeCompatiblity.MayOfProvidedType;
- } else if (providedBaseTypes.Any (t => t.Equals (typeParameter.EffectiveBaseClass))) {
- return TypeCompatiblity.MayOfProvidedType;
- }
-
- // if providedType is also a type parameter, check if base classes are compatible
- if (providedTypeParameter != null &&
- exprBaseTypes.Any (t => t.Equals (providedTypeParameter.EffectiveBaseClass)))
- return TypeCompatiblity.MayOfProvidedType;
-
- return TypeCompatiblity.NeverOfProvidedType;
- }
- // check if exprType fullfills all the type parameter constraints
- if (providedTypeParameter != null &&
- CheckTypeParameterConstraints (exprType, exprBaseTypes, providedTypeParameter))
- return TypeCompatiblity.MayOfProvidedType;
-
- switch (exprType.Kind) {
- case TypeKind.Class:
- var exprTypeDef = exprType.GetDefinition ();
- if (exprTypeDef == null)
- return TypeCompatiblity.MayOfProvidedType;
- // exprType is sealed, but providedType is not a base type of it or it does not
- // fullfill all the type parameter constraints
- if (exprTypeDef.IsSealed)
- break;
-
- // check if providedType can be a derived type
- if (providedType.Kind == TypeKind.Interface ||
- providedType.GetAllBaseTypes ().Any (t => t.Equals (exprType)))
- return TypeCompatiblity.MayOfProvidedType;
-
- if (providedTypeParameter != null &&
- exprBaseTypes.Any (t => t.Equals (providedTypeParameter.EffectiveBaseClass)))
- return TypeCompatiblity.MayOfProvidedType;
-
- break;
-
- case TypeKind.Struct:
- case TypeKind.Delegate:
- case TypeKind.Enum:
- case TypeKind.Array:
- case TypeKind.Anonymous:
- case TypeKind.Null:
- break;
-
- default:
- return TypeCompatiblity.MayOfProvidedType;
- }
- return TypeCompatiblity.NeverOfProvidedType;
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
index 8e6e92248f..e1ff416411 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
@@ -788,7 +788,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Find the candidate operators:
Predicate opFilter;
if (isExplicit)
- opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Explicit" && m.Parameters.Count == 1;
+ opFilter = m => m.IsStatic && m.IsOperator && (m.Name == "op_Explicit" || m.Name == "op_Implicit") && m.Parameters.Count == 1;
else
opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
index 2a3ce9f8eb..eb727b4faa 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
@@ -2913,7 +2913,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foreach (VariableInitializer vi in variableDeclarationStatement.Variables) {
IVariable v;
if (isConst) {
- v = MakeConstant(type, vi.NameToken, Resolve(vi.Initializer).ConstantValue);
+ ResolveResult rr = Resolve(vi.Initializer);
+ rr = resolver.ResolveCast(type, rr);
+ v = MakeConstant(type, vi.NameToken, rr.ConstantValue);
} else {
v = MakeVariable(type, vi.NameToken);
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs
index 5f2bc4180b..1af817801d 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs
@@ -138,10 +138,15 @@ class TestClass
{
if (a == 0) {
int b = 1;
- } else if (a == 1 || a == 2) {
- } else if (a == 3 || a == 4 || a == 5) {
- } else {
}
+ else
+ if (a == 1 || a == 2) {
+ }
+ else
+ if (a == 3 || a == 4 || a == 5) {
+ }
+ else {
+ }
}
}");
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/MoveToOuterScopeTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/MoveToOuterScopeTests.cs
index c9f40e5503..897d332420 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/MoveToOuterScopeTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/MoveToOuterScopeTests.cs
@@ -88,7 +88,7 @@ class A
int i = 2;
while (true) {
int j = 3;
- }
+ }
");
}
@@ -116,10 +116,10 @@ class A
}
", @"
int j;
- while (true) {
+ while (true) {
int i = 2;
j = i;
- }
+ }
");
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs
index b0eb3566e9..8d5749671a 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs
@@ -101,6 +101,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
" {" + Environment.NewLine +
" int i;" + Environment.NewLine +
" for (i = 1; i < 10; i++) {" + Environment.NewLine +
+ " " + Environment.NewLine +
" }" + Environment.NewLine +
" }" + Environment.NewLine +
"}", result);
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs
index b167903d4c..46329fc0e0 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs
@@ -209,6 +209,20 @@ class TestClass
{
nested.nested.a = nested.nested.a;
}
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void TestNoIssueWithCompoundOperator ()
+ {
+ var input = @"
+class TestClass
+{
+ void TestMethod (int a)
+ {
+ a += a;
+ }
}";
Test (input, 0);
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs
index be33b5ff15..290b346080 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs
@@ -56,7 +56,39 @@ class TestClass
void TestMethod ()
{
var x1 = (int)123;
- var x2 = (int)System.ConsoleKey.A;
+ var x2 = (short)123;
+ var x3 = (int)System.ConsoleKey.A;
+ }
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void UnknownIdentifierDoesNotCauseIncompatibleCastIssue ()
+ {
+ var input = @"
+class TestClass
+{
+ void TestMethod ()
+ {
+ var x1 = unknown as string;
+ var x2 = (string)unknown;
+ }
+}";
+
+ Test (input, 0);
+ }
+
+ [Test]
+ public void UnknownTargetTypeDoesNotCauseIncompatibleCastIssue ()
+ {
+ var input = @"
+class TestClass
+{
+ void TestMethod (int p)
+ {
+ var x1 = (unknown)p;
+ var x2 = p as unknown;
}
}";
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs
index bd7db047ff..b230d249ae 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs
@@ -90,5 +90,19 @@ class TestClass
}";
Test (input, 1, output);
}
+
+ [Test]
+ public void IntIsNotDouble ()
+ {
+ var input = @"
+sealed class TestClass
+{
+ void TestMethod (int x)
+ {
+ if (x is double) ;
+ }
+}";
+ Test (input, 0);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs
index fc73329b43..1270a20c3f 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs
@@ -92,6 +92,20 @@ class TestClass
Test (input, 1);
}
+ [Test]
+ public void TestObjectToInt ()
+ {
+ var input = @"
+sealed class TestClass
+{
+ void TestMethod (object x)
+ {
+ if (x is int) ;
+ }
+}";
+ Test (input, 0);
+ }
+
[Test]
public void TestClassIsTypeParameter ()
{
@@ -153,7 +167,8 @@ class TestClass
if (x is T) ;
}
}";
- Test (input, 1);
+ // this is possible with T==object
+ Test (input, 0);
}
[Test]
@@ -215,21 +230,6 @@ sealed class TestClass
Test (input, 1);
}
- [Test]
- public void TestTypeParameter5 ()
- {
- var input = @"
-sealed class TestClass
-{
- public TestClass (int i) { }
- void TestMethod (T x) where T : new()
- {
- if (x is TestClass) ;
- }
-}";
- Test (input, 1);
- }
-
[Test]
public void TestTypeParameterIsTypeParameter ()
{
@@ -256,6 +256,48 @@ class TestClass
{
if (x is T2) ;
}
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void TestObjectArrayToStringArray ()
+ {
+ var input = @"
+sealed class TestClass
+{
+ void TestMethod (object[] x)
+ {
+ if (x is string[]) ;
+ }
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void UnknownExpression()
+ {
+ var input = @"
+sealed class TestClass
+{
+ void TestMethod ()
+ {
+ if (unknown is string) ;
+ }
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void UnknownType()
+ {
+ var input = @"
+sealed class TestClass
+{
+ void TestMethod (int x)
+ {
+ if (x is unknown) ;
+ }
}";
Test (input, 0);
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs
index 883df7b1d2..1a50b304ca 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs
@@ -79,6 +79,7 @@ class A
throw new ArgumentException (""The parameter 'blah' can not be null"", ""blah"");
throw new ArgumentOutOfRangeException (""blah"", ""The parameter 'blah' can not be null"");
throw new DuplicateWaitObjectException (""blah"", ""The parameter 'blah' can not be null"");
+ throw new ArgumentOutOfRangeException (""blah"", 42);
}
}";
TestRefactoringContext context;
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/LocalVariableOnlyAssignedIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/LocalVariableOnlyAssignedIssueTests.cs
deleted file mode 100644
index be61be332c..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/LocalVariableOnlyAssignedIssueTests.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// LocalVariableOnlyAssignedIssueTests.cs
-//
-// Author:
-// Mansheng Yang
-//
-// Copyright (c) 2012 Mansheng Yang
-//
-// 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 ICSharpCode.NRefactory.CSharp.Refactoring;
-using NUnit.Framework;
-
-namespace ICSharpCode.NRefactory.CSharp.CodeIssues
-{
- [TestFixture]
- public class LocalVariableOnlyAssignedIssueTests : InspectionActionTestBase
- {
- [Test]
- public void TestUnusedValue ()
- {
- var input1 = @"
-class TestClass
-{
- void TestMethod()
- {
- int i = 1;
- i++;
- }
-}";
- Test (input1, 1);
-
- var input2 = @"
-class TestClass
-{
- void TestMethod()
- {
- int i;
- i = 1;
- }
-}";
- Test (input2, 1);
- }
-
- [Test]
- public void TestUsedValue ()
- {
- var input = @"
-class TestClass
-{
- int TestMethod()
- {
- int i;
- i = 1;
- int j = i + 1;
- return j;
- }
-}";
- Test (input, 0);
- }
-
- [Test]
- public void TestOutArgument ()
- {
- var input1 = @"
-class TestClass
-{
- void Test (out int i)
- {
- i = 1;
- }
- void TestMethod()
- {
- int i = 1;
- Test (out i);
- }
-}";
- Test (input1, 1);
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs
index 2e5e4f5c1f..58b4db6a5d 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs
@@ -87,5 +87,19 @@ class TestClass
}";
Test (input, 1);
}
+
+ [Test]
+ public void YieldBreak ()
+ {
+ var input = @"
+class TestClass
+{
+ System.Collections.Generic.IEnumerable TestMethod ()
+ {
+ yield break;
+ }
+}";
+ Test (input, 0);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs
index 14df3a1dd3..5c72a57eea 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs
@@ -68,6 +68,18 @@ class TestClass
{
void TestMethod (int a, int b = 1, int c = 1)
{ }
+}";
+ Test (input, 0);
+ }
+
+ [Test]
+ public void TestNoIssue_Generics ()
+ {
+ var input = @"
+class TestClass
+{
+ void TestMethod (object obj) { }
+ void TestMethod (object obj, int arg = 0) { }
}";
Test (input, 0);
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MissingStringComparisonIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MissingStringComparisonIssueTests.cs
new file mode 100644
index 0000000000..25fcae8768
--- /dev/null
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MissingStringComparisonIssueTests.cs
@@ -0,0 +1,93 @@
+//
+// Author:
+// Daniel Grunwald
+//
+// Copyright (c) 2012 Daniel Grunwald
+//
+// 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 NUnit.Framework;
+
+namespace ICSharpCode.NRefactory.CSharp.CodeIssues
+{
+ [TestFixture]
+ public class MissingStringComparisonIssueTests : InspectionActionTestBase
+ {
+ const string stringIndexOfStringCalls = @"using System;
+using System.Collections.Generic;
+class Test {
+ public void StringIndexOfStringCalls(List list)
+ {
+ list[0].IndexOf("".com"");
+ list[0].IndexOf("".com"", 0);
+ list[0].IndexOf("".com"", 0, 5);
+ list[0].IndexOf(list[1], 0, 10);
+ }
+}";
+ const string stringIndexOfStringCallsWithComparison = @"using System;
+using System.Collections.Generic;
+class Test {
+ public void StringIndexOfStringCalls(List list)
+ {
+ list [0].IndexOf ("".com"", StringComparison.Ordinal);
+ list [0].IndexOf ("".com"", 0, StringComparison.Ordinal);
+ list [0].IndexOf ("".com"", 0, 5, StringComparison.Ordinal);
+ list [0].IndexOf (list [1], 0, 10, StringComparison.Ordinal);
+ }
+}";
+
+ [Test]
+ public void IndexOfStringCalls()
+ {
+ Test(stringIndexOfStringCalls, 4, stringIndexOfStringCallsWithComparison);
+ }
+
+ [Test]
+ public void IndexOfStringCallsAlreadyWithComparison()
+ {
+ Test(stringIndexOfStringCallsWithComparison, 0);
+ }
+
+ [Test]
+ public void StringIndexOfChar()
+ {
+ string program = @"using System;
+class Test {
+ void M(string text) {
+ text.IndexOf('.');
+ }
+}";
+ Test(program, 0);
+ }
+
+ [Test]
+ public void ListIndexOf()
+ {
+ string program = @"using System.Collections.Generic;
+class Test {
+ void M(List list) {
+ list.IndexOf("".com"");
+ }
+}";
+ Test(program, 0);
+ }
+ }
+}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs
index e939c3cfa0..5b47df9c4e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs
@@ -114,5 +114,21 @@ class TestClass {
}";
Test (input, 0);
}
+
+
+ [Test]
+ public void TestMethodUsedAsDelegateMethod ()
+ {
+ var input = @"using System;
+class TestClass {
+ public event EventHandler FooEvt;
+ void TestMethod ()
+ {
+ FooEvt += FooBar;
+ }
+ void FooBar (object sender, EventArgs e) {}
+}";
+ Test (input, 0);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantWhereWithPredicateIssueTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantWhereWithPredicateIssueTests.cs
index 9c712e6726..fc40866ca6 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantWhereWithPredicateIssueTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantWhereWithPredicateIssueTests.cs
@@ -66,5 +66,28 @@ public class X
var issues = GetIssues (new RedundantWhereWithPredicateIssue (), input, out context);
Assert.AreEqual (0, issues.Count);
}
+
+ [Test]
+ public void TestWhereCount()
+ {
+ var input = @"using System.Linq;
+public class CSharpDemo {
+ public void Bla () {
+ int[] arr;
+ var bla = arr.Where (x => x < 4).Count ();
+ }
+}";
+
+ TestRefactoringContext context;
+ var issues = GetIssues (new RedundantWhereWithPredicateIssue (), input, out context);
+ Assert.AreEqual (1, issues.Count);
+ CheckFix (context, issues, @"using System.Linq;
+public class CSharpDemo {
+ public void Bla () {
+ int[] arr;
+ var bla = arr.Count (x => x < 4);
+ }
+}");
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs
index c46e2b872e..f357818b34 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs
@@ -299,6 +299,28 @@ class B : A
var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context);
Assert.AreEqual(0, issues.Count);
}
+
+ [Test]
+ public void IgnoresCuriouslyRecurringTemplatePattern()
+ {
+ var input = @"
+class Base
+{
+ public static void F() { }
+}
+class Derived : Base {}
+class Test
+{
+ void Main()
+ {
+ Derived.F();
+ }
+}";
+ // do not suggest replacing 'Derived.F()' with 'Base.F()'
+ TestRefactoringContext context;
+ var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context);
+ Assert.AreEqual(0, issues.Count);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/StringIsNullOrEmptyInspectorTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/StringIsNullOrEmptyInspectorTests.cs
index d256ca5682..28f6431a58 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/StringIsNullOrEmptyInspectorTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/StringIsNullOrEmptyInspectorTests.cs
@@ -499,5 +499,23 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
}
}");
}
+
+ [Test]
+ public void TestArrays ()
+ {
+ var input = @"class Foo
+{
+ void Bar ()
+ {
+ int[] foo = new int[10];
+ if (foo == null || foo.Length == 0) {
+ }
+ }
+}";
+
+ TestRefactoringContext context;
+ var issues = GetIssues (new StringIsNullOrEmptyIssue (), input, out context);
+ Assert.AreEqual (0, issues.Count);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs
index f1de52cf6d..a3327d82f6 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs
@@ -76,9 +76,11 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
var input = @"class A
{
delegate void TestEventHandler ();
+ TestEventHandler eventTested;
event TestEventHandler EventTested
{
add {
+ eventTested += value;
}
remove {
}
@@ -86,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
}";
TestRefactoringContext context;
var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context);
- Assert.AreEqual(2, issues.Count);
+ Assert.AreEqual(1, issues.Count);
}
[Test]
@@ -153,6 +155,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
throw new Exception();
}
}
+}";
+ TestRefactoringContext context;
+ var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context);
+ Assert.AreEqual(0, issues.Count);
+ }
+
+ [Test]
+ public void DoesNotWarnOnEmptyCustomEvent()
+ {
+ // Empty custom events are often used when the event can never be raised
+ // by a class (but the event is required e.g. due to an interface).
+ var input = @"class A
+{
+ delegate void TestEventHandler ();
+ event TestEventHandler EventTested
+ {
+ add { }
+ remove { }
+ }
}";
TestRefactoringContext context;
var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context);
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
index 99f8be6f85..07d98aeb52 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
@@ -97,5 +97,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
AssertError(typeof(StringComparison), resolver.WithCheckForOverflow(true).ResolveCast(ResolveType(typeof(StringComparison)), MakeConstant(long.MaxValue)));
}
+
+ [Test]
+ public void ImplicitCastInConstant()
+ {
+ string program = @"using System;
+class Test {
+ const int $MAXSIZE = ushort.MaxValue;
+}";
+ var rr = ResolveAtLocation(program);
+ IField field = (IField)rr.Member;
+ Assert.IsTrue(field.IsConst);
+ Assert.AreEqual("System.Int32", field.Type.FullName);
+ Assert.AreEqual(typeof(int), field.ConstantValue.GetType());
+ Assert.AreEqual(ushort.MaxValue, (int)field.ConstantValue);
+ }
+
+ [Test]
+ public void ImplicitCastInLocalConstant()
+ {
+ string program = @"using System;
+class Test {
+ void M() {
+ const int $MAXSIZE = ushort.MaxValue;
+ }
+}";
+ var rr = ResolveAtLocation(program);
+ Assert.IsTrue(rr.Variable.IsConst);
+ Assert.AreEqual("System.Int32", rr.Variable.Type.FullName);
+ Assert.AreEqual(typeof(int), rr.Variable.ConstantValue.GetType());
+ Assert.AreEqual(ushort.MaxValue, (int)rr.Variable.ConstantValue);
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs
index f8395cdabf..4d9bbd7fe0 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs
@@ -490,6 +490,24 @@ class C {
Assert.AreEqual("B", rr.Input.Type.Name);
}
+ [Test]
+ public void ImplicitUserDefinedConversionFollowedByExplicitNumericConversion()
+ {
+ var rr = Resolve(@"
+ struct T {
+ public static implicit operator float(T t) { return 0; }
+ }
+ class Test {
+ void Run(T t) {
+ int x = $(int)t$;
+ }
+ }");
+ Assert.IsTrue(rr.Conversion.IsValid);
+ Assert.IsTrue(rr.Conversion.IsUserDefined);
+ // even though the user-defined conversion is implicit, the combined conversion is explicit
+ Assert.IsTrue(rr.Conversion.IsExplicit);
+ }
+
[Test]
[Ignore("Not implemented yet.")]
public void BothDirectConversionAndBaseClassConversionAvailable()
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
index f4296dd82b..b68e0e5343 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
@@ -110,9 +110,9 @@
-
+
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
index 9d4b360635..7e0a89d8f8 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
@@ -107,7 +107,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
///
/// Gets the effective interface set of this type parameter.
///
- IList EffectiveInterfaceSet { get; }
+ ICollection EffectiveInterfaceSet { get; }
///
/// Gets if the type parameter has the 'new()' constraint.
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
index 8b12e0e920..cede6c7a8b 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
@@ -94,48 +94,73 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IType EffectiveBaseClass {
get {
- if (effectiveBaseClass == null)
- effectiveBaseClass = CalculateEffectiveBaseClass();
+ if (effectiveBaseClass == null) {
+ // protect against cyclic type parameters
+ using (var busyLock = BusyManager.Enter(this)) {
+ if (!busyLock.Success)
+ return SpecialType.UnknownType; // don't cache this error
+ effectiveBaseClass = CalculateEffectiveBaseClass();
+ }
+ }
return effectiveBaseClass;
}
}
IType CalculateEffectiveBaseClass()
{
- // protect against cyclic type parameters
- using (var busyLock = BusyManager.Enter(this)) {
- if (!busyLock.Success)
- return SpecialType.UnknownType;
-
- if (HasValueTypeConstraint)
- return this.Compilation.FindType(KnownTypeCode.ValueType);
-
- List classTypeConstraints = new List();
- foreach (IType constraint in this.DirectBaseTypes) {
- if (constraint.Kind == TypeKind.Class) {
- classTypeConstraints.Add(constraint);
- } else if (constraint.Kind == TypeKind.TypeParameter) {
- IType baseClass = ((ITypeParameter)constraint).EffectiveBaseClass;
- if (baseClass.Kind == TypeKind.Class)
- classTypeConstraints.Add(baseClass);
- }
- }
- if (classTypeConstraints.Count == 0)
- return this.Compilation.FindType(KnownTypeCode.Object);
- // Find the derived-most type in the resulting set:
- IType result = classTypeConstraints[0];
- for (int i = 1; i < classTypeConstraints.Count; i++) {
- if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition()))
- result = classTypeConstraints[i];
+ if (HasValueTypeConstraint)
+ return this.Compilation.FindType(KnownTypeCode.ValueType);
+
+ List classTypeConstraints = new List();
+ foreach (IType constraint in this.DirectBaseTypes) {
+ if (constraint.Kind == TypeKind.Class) {
+ classTypeConstraints.Add(constraint);
+ } else if (constraint.Kind == TypeKind.TypeParameter) {
+ IType baseClass = ((ITypeParameter)constraint).EffectiveBaseClass;
+ if (baseClass.Kind == TypeKind.Class)
+ classTypeConstraints.Add(baseClass);
}
- return result;
}
+ if (classTypeConstraints.Count == 0)
+ return this.Compilation.FindType(KnownTypeCode.Object);
+ // Find the derived-most type in the resulting set:
+ IType result = classTypeConstraints[0];
+ for (int i = 1; i < classTypeConstraints.Count; i++) {
+ if (classTypeConstraints[i].GetDefinition().IsDerivedFrom(result.GetDefinition()))
+ result = classTypeConstraints[i];
+ }
+ return result;
}
- public IList EffectiveInterfaceSet {
+ ICollection effectiveInterfaceSet;
+
+ public ICollection EffectiveInterfaceSet {
get {
- throw new NotImplementedException();
+ var result = LazyInit.VolatileRead(ref effectiveInterfaceSet);
+ if (result != null) {
+ return result;
+ } else {
+ // protect against cyclic type parameters
+ using (var busyLock = BusyManager.Enter(this)) {
+ if (!busyLock.Success)
+ return EmptyList.Instance; // don't cache this error
+ return LazyInit.GetOrSet(ref effectiveInterfaceSet, CalculateEffectiveInterfaceSet());
+ }
+ }
+ }
+ }
+
+ ICollection CalculateEffectiveInterfaceSet()
+ {
+ HashSet result = new HashSet();
+ foreach (IType constraint in this.DirectBaseTypes) {
+ if (constraint.Kind == TypeKind.Interface) {
+ result.Add(constraint);
+ } else if (constraint.Kind == TypeKind.TypeParameter) {
+ result.UnionWith(((ITypeParameter)constraint).EffectiveInterfaceSet);
+ }
}
+ return result;
}
public abstract bool HasDefaultConstructorConstraint { get; }
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs
index 22e7fc4fc8..f0ec26d0e1 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs
@@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return SpecialType.UnknownType; }
}
- IList ITypeParameter.EffectiveInterfaceSet {
+ ICollection ITypeParameter.EffectiveInterfaceSet {
get { return EmptyList.Instance; }
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs
index adcd1a8e34..c28e553a5e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs
@@ -48,12 +48,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
KnownTypeReference typeRef = KnownTypeReference.Get(typeCode);
if (typeRef == null)
return SpecialType.UnknownType;
+ var typeName = new TopLevelTypeName(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount);
foreach (IAssembly asm in compilation.Assemblies) {
- var typeDef = asm.GetTypeDefinition(new TopLevelTypeName(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount));
+ var typeDef = asm.GetTypeDefinition(typeName);
if (typeDef != null)
return typeDef;
}
- return new UnknownType(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount);
+ return new UnknownType(typeName);
}
}
}