Browse Source

Merge NRefactory 5.2.0-464-g536b9b0 into SharpDevelop newNR branch.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
971cd13e08
  1. 55
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
  2. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs
  3. 15
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
  4. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  5. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs
  6. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs
  7. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs
  8. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs
  9. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CastExpressionOfIncompatibleTypeIssue.cs
  10. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs
  11. 15
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs
  12. 32
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs
  13. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs
  14. 30
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs
  15. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodOverloadHidesOptionalParameterIssue.cs
  16. 106
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MissingStringComparisonIssue.cs
  17. 48
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs
  18. 27
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs
  19. 58
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs
  20. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
  21. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ValueParameterUnusedIssue.cs
  22. 45
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs
  23. 69
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs
  24. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs
  25. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs
  26. 13
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs
  27. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
  28. 128
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs
  29. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  30. 4
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  31. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs
  32. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs
  33. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs
  34. 34
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs
  35. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs
  36. 72
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs
  37. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs
  38. 97
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/LocalVariableOnlyAssignedIssueTests.cs
  39. 14
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs
  40. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs
  41. 93
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MissingStringComparisonIssueTests.cs
  42. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs
  43. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/RedundantWhereWithPredicateIssueTests.cs
  44. 22
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs
  45. 18
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/StringIsNullOrEmptyInspectorTests.cs
  46. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs
  47. 31
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
  48. 18
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs
  49. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
  50. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs
  51. 43
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
  52. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs
  53. 5
      src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs

55
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 // 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 // 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.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Analysis namespace ICSharpCode.NRefactory.CSharp.Analysis
{ {
@ -750,5 +751,57 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return CreateConnectedEndNode(fixedStatement, bodyEnd); return CreateConnectedEndNode(fixedStatement, bodyEnd);
} }
} }
/// <summary>
/// Debugging helper that exports a control flow graph.
/// </summary>
public static GraphVizGraph ExportGraph(IList<ControlFlowNode> nodes)
{
GraphVizGraph g = new GraphVizGraph();
GraphVizNode[] n = new GraphVizNode[nodes.Count];
Dictionary<ControlFlowNode, int> dict = new Dictionary<ControlFlowNode, int>();
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;
}
} }
} }

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ReachabilityAnalysis.cs

@ -78,6 +78,10 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
} }
} }
public IEnumerable<Statement> ReachableStatements {
get { return reachableStatements; }
}
public bool IsReachable(Statement statement) public bool IsReachable(Statement statement)
{ {
return reachableStatements.Contains(statement); return reachableStatements.Contains(statement);

15
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs

@ -119,16 +119,20 @@ namespace ICSharpCode.NRefactory.CSharp
protected override void VisitChildren (AstNode node) protected override void VisitChildren (AstNode node)
{ {
if (!FormattingRegion.IsEmpty) {
if (node.EndLocation < FormattingRegion.Begin || node.StartLocation > FormattingRegion.End)
return;
}
AstNode next; AstNode next;
for (var child = node.FirstChild; child != null; child = next) { for (var child = node.FirstChild; child != null; child = next) {
// Store next to allow the loop to continue // Store next to allow the loop to continue
// if the visitor removes/replaces child. // if the visitor removes/replaces child.
next = child.NextSibling; next = child.NextSibling;
if (!FormattingRegion.IsEmpty) {
if (child.EndLocation < FormattingRegion.Begin) {
continue;
}
if (child.StartLocation > FormattingRegion.End) {
break;
}
}
child.AcceptVisitor (this); child.AcceptVisitor (this);
} }
} }
@ -404,6 +408,7 @@ namespace ICSharpCode.NRefactory.CSharp
void ForceSpace(int startOffset, int endOffset, bool forceSpace) void ForceSpace(int startOffset, int endOffset, bool forceSpace)
{ {
int lastNonWs = SearchLastNonWsChar(startOffset, endOffset); int lastNonWs = SearchLastNonWsChar(startOffset, endOffset);
if (lastNonWs >= 0)
AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : ""); AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : "");
} }
// void ForceSpacesAfter (AstNode n, bool forceSpaces) // void ForceSpacesAfter (AstNode n, bool forceSpaces)

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -301,6 +301,7 @@
<Compile Include="Refactoring\CodeIssues\ExpressionIsNeverOfProvidedTypeIssue.cs" /> <Compile Include="Refactoring\CodeIssues\ExpressionIsNeverOfProvidedTypeIssue.cs" />
<Compile Include="Refactoring\CodeIssues\MethodNeverReturnsIssue.cs" /> <Compile Include="Refactoring\CodeIssues\MethodNeverReturnsIssue.cs" />
<Compile Include="Refactoring\CodeIssues\MethodOverloadHidesOptionalParameterIssue.cs" /> <Compile Include="Refactoring\CodeIssues\MethodOverloadHidesOptionalParameterIssue.cs" />
<Compile Include="Refactoring\CodeIssues\MissingStringComparisonIssue.cs" />
<Compile Include="Refactoring\CodeIssues\NegativeRelationalExpressionIssue.cs" /> <Compile Include="Refactoring\CodeIssues\NegativeRelationalExpressionIssue.cs" />
<Compile Include="Refactoring\CodeIssues\ExplicitConversionInForEachIssue.cs" /> <Compile Include="Refactoring\CodeIssues\ExplicitConversionInForEachIssue.cs" />
<Compile Include="Refactoring\CodeIssues\ForControlVariableNotModifiedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\ForControlVariableNotModifiedIssue.cs" />
@ -316,11 +317,11 @@
<Compile Include="Refactoring\CodeIssues\RedundantObjectOrCollectionInitializerIssue.cs" /> <Compile Include="Refactoring\CodeIssues\RedundantObjectOrCollectionInitializerIssue.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantTypeCastIssue.cs" /> <Compile Include="Refactoring\CodeIssues\RedundantTypeCastIssue.cs" />
<Compile Include="Refactoring\CodeIssues\ReferenceEqualsCalledWithValueTypeIssue.cs" /> <Compile Include="Refactoring\CodeIssues\ReferenceEqualsCalledWithValueTypeIssue.cs" />
<Compile Include="Refactoring\CodeIssues\ResultOfAsyncCallShouldNotBeIgnoredIssue.cs" />
<Compile Include="Refactoring\CodeIssues\UnreachableCodeIssue.cs" /> <Compile Include="Refactoring\CodeIssues\UnreachableCodeIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\LocalVariableHidesMemberIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\LocalVariableHidesMemberIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\ParameterHidesMemberIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\ParameterHidesMemberIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\VariableHidesMemberIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableHidesMemberIssue\VariableHidesMemberIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableOnlyAssignedIssues\LocalVariableOnlyAssignedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\LocalVariableNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\LocalVariableNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\ParameterNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\VariableNotUsedIssues\ParameterNotUsedIssue.cs" />
<Compile Include="Refactoring\CodeIssues\TypeParameterNotUsedIssue.cs" /> <Compile Include="Refactoring\CodeIssues\TypeParameterNotUsedIssue.cs" />
@ -333,7 +334,6 @@
<Compile Include="Refactoring\RefactoringAstHelper.cs" /> <Compile Include="Refactoring\RefactoringAstHelper.cs" />
<Compile Include="Refactoring\RefactoringContext.cs" /> <Compile Include="Refactoring\RefactoringContext.cs" />
<Compile Include="Refactoring\Script.cs" /> <Compile Include="Refactoring\Script.cs" />
<Compile Include="Refactoring\TypeCompatibilityHelper.cs" />
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" /> <Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="Refactoring\VariableReferenceGraph.cs" /> <Compile Include="Refactoring\VariableReferenceGraph.cs" />
<Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" /> <Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" />

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs

@ -122,6 +122,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
return resolver.GetConversion(expression, cancellationToken); return resolver.GetConversion(expression, cancellationToken);
} }
public TypeSystemAstBuilder CreateTypeSytemAstBuilder(AstNode node)
{
var csResolver = resolver.GetResolverStateBefore(node);
return new TypeSystemAstBuilder(csResolver);
}
#endregion #endregion
#region Code Analyzation #region Code Analyzation

7
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IterateViaForeachAction.cs

@ -70,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var blockStatement = new BlockStatement(); var blockStatement = new BlockStatement();
blockStatement.Statements.Add(iterator); blockStatement.Statements.Add(iterator);
script.Replace(usingStatement.EmbeddedStatement, blockStatement); script.Replace(usingStatement.EmbeddedStatement, blockStatement);
script.FormatText(blockStatement); script.FormatText((AstNode)blockStatement);
} else if (usingStatement.EmbeddedStatement is BlockStatement) { } else if (usingStatement.EmbeddedStatement is BlockStatement) {
var anchorNode = usingStatement.EmbeddedStatement.FirstChild; var anchorNode = usingStatement.EmbeddedStatement.FirstChild;
script.InsertAfter(anchorNode, iterator); script.InsertAfter(anchorNode, iterator);
@ -149,11 +149,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
IType collectionType = null; IType collectionType = null;
foreach (var baseType in type.GetAllBaseTypes()) { foreach (var baseType in type.GetAllBaseTypes()) {
var baseTypeDefinition = baseType.GetDefinition(); if (baseType.IsKnownType(KnownTypeCode.IEnumerableOfT)) {
if (baseTypeDefinition.IsKnownType(KnownTypeCode.IEnumerableOfT)) {
collectionType = baseType; collectionType = baseType;
break; break;
} else if (baseTypeDefinition.IsKnownType(KnownTypeCode.IEnumerable)) { } else if (baseType.IsKnownType(KnownTypeCode.IEnumerable)) {
collectionType = baseType; collectionType = baseType;
// Don't break, continue in case type implements IEnumerable<T> // Don't break, continue in case type implements IEnumerable<T>
} }

7
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) { } else if (parent is OperatorDeclaration) {
body = ((OperatorDeclaration)parent).Body; body = ((OperatorDeclaration)parent).Body;
} }
if (body != null) if (body != null) {
CheckVariable (((LocalResolveResult)ctx.Resolve (parameterDeclaration)).Variable, body); var lrr = ctx.Resolve (parameterDeclaration) as LocalResolveResult;
if (lrr != null)
CheckVariable (lrr.Variable, body);
}
base.VisitParameterDeclaration (parameterDeclaration); base.VisitParameterDeclaration (parameterDeclaration);
} }

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AssignmentMadeToSameVariableIssue.cs

@ -56,6 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
base.VisitAssignmentExpression (assignmentExpression); base.VisitAssignmentExpression (assignmentExpression);
if (assignmentExpression.Operator != AssignmentOperatorType.Assign)
return;
if (!(assignmentExpression.Left is IdentifierExpression) && if (!(assignmentExpression.Left is IdentifierExpression) &&
!(assignmentExpression.Left is MemberReferenceExpression)) !(assignmentExpression.Left is MemberReferenceExpression))
return; return;

2
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) void VisitTypeCastExpression (Expression expression, IType exprType, IType castToType)
{ {
if (exprType.Kind == TypeKind.Unknown || castToType.Kind == TypeKind.Unknown)
return;
var foundConversion = conversion.ExplicitConversion(exprType, castToType); var foundConversion = conversion.ExplicitConversion(exprType, castToType);
if (foundConversion == Conversion.None) if (foundConversion == Conversion.None)
AddIssue (expression, ctx.TranslateString ("Type cast expression of incompatible type")); AddIssue (expression, ctx.TranslateString ("Type cast expression of incompatible type"));

14
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) 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"; floatType = "double";
AddIssue (binaryOperatorExpr, string.Format(ctx.TranslateString ("Use {0}.IsNan()"), floatType), AddIssue(binaryOperatorExpr, string.Format(ctx.TranslateString ("Use {0}.IsNaN()"), floatType),
script => { script => {
Expression expr = new InvocationExpression (new MemberReferenceExpression ( Expression expr = new PrimitiveType(floatType).Invoke("IsNaN", argExpr.Clone());
new TypeReferenceExpression (new PrimitiveType (floatType)), "IsNaN"), argExpr.Clone ());
if (binaryOperatorExpr.Operator == BinaryOperatorType.InEquality) if (binaryOperatorExpr.Operator == BinaryOperatorType.InEquality)
expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr); expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr);
script.Replace (binaryOperatorExpr, expr); script.Replace (binaryOperatorExpr, expr);
@ -109,13 +108,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
AddIssue (binaryOperatorExpression, ctx.TranslateString ("Compare a difference with EPSILON"), AddIssue (binaryOperatorExpression, ctx.TranslateString ("Compare a difference with EPSILON"),
script => { script => {
// Math.Abs(diff) op EPSILON // Math.Abs(diff) op EPSILON
var builder = ctx.CreateTypeSytemAstBuilder(binaryOperatorExpression);
var diff = new BinaryOperatorExpression (binaryOperatorExpression.Left.Clone (), var diff = new BinaryOperatorExpression (binaryOperatorExpression.Left.Clone (),
BinaryOperatorType.Subtract, binaryOperatorExpression.Right.Clone ()); BinaryOperatorType.Subtract, binaryOperatorExpression.Right.Clone ());
var abs = new InvocationExpression ( var abs = builder.ConvertType(new TopLevelTypeName("System", "Math")).Invoke("Abs", diff);
new MemberReferenceExpression (
new TypeReferenceExpression (new SimpleType ("System.Math")),
"Abs"),
diff);
var op = binaryOperatorExpression.Operator == BinaryOperatorType.Equality ? var op = binaryOperatorExpression.Operator == BinaryOperatorType.Equality ?
BinaryOperatorType.LessThan : BinaryOperatorType.GreaterThan; BinaryOperatorType.LessThan : BinaryOperatorType.GreaterThan;
var epsilon = new IdentifierExpression ("EPSILON"); var epsilon = new IdentifierExpression ("EPSILON");

15
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs

@ -27,6 +27,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -44,11 +45,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
static CSharpConversions conversion; readonly CSharpConversions conversions;
public GatherVisitor (BaseRefactoringContext ctx) public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx) : base (ctx)
{ {
conversion = new CSharpConversions(ctx.Compilation); conversions = CSharpConversions.Get(ctx.Compilation);
} }
public override void VisitIsExpression (IsExpression isExpression) public override void VisitIsExpression (IsExpression isExpression)
@ -58,8 +59,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var type = ctx.Resolve (isExpression.Expression).Type; var type = ctx.Resolve (isExpression.Expression).Type;
var providedType = ctx.ResolveType (isExpression.Type); var providedType = ctx.ResolveType (isExpression.Type);
var foundConversion = conversion.ImplicitConversion(type, providedType); var foundConversion = conversions.ImplicitConversion(type, providedType);
if (foundConversion == Conversion.None) if (!IsValidReferenceOrBoxingConversion(type, providedType))
return; return;
var action = new CodeAction (ctx.TranslateString ("Compare with 'null'"), 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. " + AddIssue (isExpression, ctx.TranslateString ("Given expression is always of the provided type. " +
"Consider comparing with 'null' instead"), new [] { action }); "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);
}
} }
} }
} }

32
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs

@ -25,6 +25,10 @@
// THE SOFTWARE. // THE SOFTWARE.
using System.Collections.Generic; 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 namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -42,22 +46,46 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
readonly CSharpConversions conversions;
public GatherVisitor (BaseRefactoringContext ctx) public GatherVisitor (BaseRefactoringContext ctx)
: base (ctx) : base (ctx)
{ {
conversions = CSharpConversions.Get(ctx.Compilation);
} }
public override void VisitIsExpression (IsExpression isExpression) public override void VisitIsExpression (IsExpression isExpression)
{ {
base.VisitIsExpression (isExpression); base.VisitIsExpression (isExpression);
var conversions = CSharpConversions.Get(ctx.Compilation);
var exprType = ctx.Resolve (isExpression.Expression).Type; var exprType = ctx.Resolve (isExpression.Expression).Type;
var providedType = ctx.ResolveType (isExpression.Type); var providedType = ctx.ResolveType (isExpression.Type);
if (TypeCompatibilityHelper.CheckTypeCompatibility(exprType, providedType) == if (exprType.Kind == TypeKind.Unknown || providedType.Kind == TypeKind.Unknown)
TypeCompatibilityHelper.TypeCompatiblity.NeverOfProvidedType) 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")); 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);
}
} }
} }
} }

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IncorrectExceptionParameterOrderingIssue.cs

@ -63,8 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
var firstParam = parameters.FirstOrNullObject() as PrimitiveExpression; var firstParam = parameters.FirstOrNullObject() as PrimitiveExpression;
var secondParam = parameters.LastOrNullObject() as PrimitiveExpression; var secondParam = parameters.LastOrNullObject() as PrimitiveExpression;
if (firstParam == null || firstParam.Value.GetType() != typeof(string) || if (firstParam == null || !(firstParam.Value is string) ||
secondParam == null || firstParam.Value.GetType() != typeof(string)) secondParam == null || !(secondParam.Value is string))
return; return;
var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult; var type = context.Resolve(objectCreateExpression.Type) as TypeResolveResult;
if (type == null) if (type == null)

30
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MethodNeverReturnsIssue.cs

@ -43,8 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase class GatherVisitor : GatherVisitorBase
{ {
readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
public GatherVisitor(BaseRefactoringContext ctx) public GatherVisitor(BaseRefactoringContext ctx)
: base (ctx) : base (ctx)
{ {
@ -58,31 +56,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (methodDeclaration.Body.IsNull) if (methodDeclaration.Body.IsNull)
return; return;
var cfg = cfgBuilder.BuildControlFlowGraph (methodDeclaration.Body, ctx.Resolver, var reachability = ctx.CreateReachabilityAnalysis(methodDeclaration.Body);
ctx.CancellationToken); bool hasReachableReturn = false;
var stack = new Stack<ControlFlowNode> (); foreach (var statement in reachability.ReachableStatements) {
var visitedNodes = new HashSet<ControlFlowNode> (); if (statement is ReturnStatement || statement is ThrowStatement || statement is YieldBreakStatement) {
stack.Push (cfg [0]); hasReachableReturn = true;
while (stack.Count > 0) { break;
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);
} }
} }
if (!hasReachableReturn && !reachability.IsEndpointReachable(methodDeclaration.Body)) {
AddIssue (methodDeclaration.NameToken, AddIssue (methodDeclaration.NameToken,
ctx.TranslateString ("Method never reaches its end or a 'return' statement.")); ctx.TranslateString ("Method never reaches its end or a 'return' statement."));
} }
} }
} }
} }
}

2
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) if (method.Parameters.Count == 0 || !method.Parameters.Last ().IsOptional)
return; return;
var overloads = method.DeclaringType.GetMembers (m => m.Name == method.Name).OfType<IMethod> () var overloads = method.DeclaringType.GetMethods(m => m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count)
.ToArray (); .ToArray ();
var parameterNodes = methodDeclaration.Parameters.ToArray(); var parameterNodes = methodDeclaration.Parameters.ToArray();

106
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/MissingStringComparisonIssue.cs

@ -0,0 +1,106 @@
//
// MissingStringComparisonIssue.cs
//
// Author:
// Daniel Grunwald <daniel@danielgrunwald.de>
//
// 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<CodeIssue> 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);
}
}
}
}

48
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantWhereWithPredicateIssue.cs

@ -6,7 +6,7 @@ using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring 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().", Description= "Detects redundant Where() with predicate calls followed by Any().",
Category = IssueCategories.CodeQualityIssues, Category = IssueCategories.CodeQualityIssues,
Severity = Severity.Hint)] Severity = Severity.Hint)]
@ -19,7 +19,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
new InvocationExpression ( new InvocationExpression (
new MemberReferenceExpression (new AnyNode ("target"), "Where"), new MemberReferenceExpression (new AnyNode ("target"), "Where"),
new AnyNode ())), new AnyNode ())),
"Any")); Pattern.AnyString));
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{ {
@ -41,11 +41,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
var anyResolve = ctx.Resolve (anyInvoke) as InvocationResolveResult; var anyResolve = ctx.Resolve (anyInvoke) as InvocationResolveResult;
if (anyResolve == null || anyResolve.Member.FullName != "System.Linq.Enumerable.Any") if (anyResolve == null || !HasPredicateVersion(anyResolve.Member))
return; return;
var whereInvoke = match.Get<InvocationExpression> ("whereInvoke").Single (); var whereInvoke = match.Get<InvocationExpression> ("whereInvoke").Single ();
var whereResolve = ctx.Resolve (whereInvoke) as InvocationResolveResult; 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; return;
if (whereResolve.Member.Parameters.Count != 2) if (whereResolve.Member.Parameters.Count != 2)
return; return;
@ -53,12 +53,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (predResolve.Type.TypeParameterCount != 2) if (predResolve.Type.TypeParameterCount != 2)
return; return;
AddIssue (anyInvoke, "Redundant Where() call with predicate followed by Any()", script => { AddIssue (
anyInvoke, string.Format("Redundant Where() call with predicate followed by {0}()", anyResolve.Member.Name),
script => {
var arg = whereInvoke.Arguments.Single ().Clone (); var arg = whereInvoke.Arguments.Single ().Clone ();
var target = match.Get<Expression> ("target").Single ().Clone (); var target = match.Get<Expression> ("target").Single ().Clone ();
script.Replace (anyInvoke, new InvocationExpression (new MemberReferenceExpression (target, "Any"), arg)); 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;
}
}
} }
} }
} }

27
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ReferenceToStaticMemberViaDerivedTypeIssue.cs

@ -89,6 +89,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
if (typeResolveResult.Type.Equals(member.DeclaringType)) if (typeResolveResult.Type.Equals(member.DeclaringType))
return; 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"), AddIssue(issueAnchor, context.TranslateString("Static method invoked via derived type"),
GetActions(context, targetExpression, member)); GetActions(context, targetExpression, member));
} }
@ -96,14 +102,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IEnumerable<CodeAction> GetActions(BaseRefactoringContext context, Expression targetExpression, IEnumerable<CodeAction> GetActions(BaseRefactoringContext context, Expression targetExpression,
IMember member) IMember member)
{ {
var csResolver = context.Resolver.GetResolverStateBefore(targetExpression); var builder = context.CreateTypeSytemAstBuilder(targetExpression);
var builder = new TypeSystemAstBuilder(csResolver);
var newType = builder.ConvertType(member.DeclaringType); var newType = builder.ConvertType(member.DeclaringType);
string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText()); string description = string.Format("{0} '{1}'", context.TranslateString("Use base class"), newType.GetText());
yield return new CodeAction(description, script => { yield return new CodeAction(description, script => {
script.Replace(targetExpression, newType); 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 #endregion
} }

58
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<CodeIssue> 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");
}
}
}
}
}

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs

@ -31,7 +31,7 @@ using ICSharpCode.NRefactory.PatternMatching;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
/// <summary> /// <summary>
/// Checks for str == null && str == "" /// Checks for str == null &amp;&amp; str == " "
/// Converts to: string.IsNullOrEmpty (str) /// Converts to: string.IsNullOrEmpty (str)
/// </summary> /// </summary>
[IssueDescription("Use string.IsNullOrEmpty", [IssueDescription("Use string.IsNullOrEmpty",
@ -124,6 +124,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} }
if (m.Success) { if (m.Success) {
var str = m.Get<Expression>("str").Single(); var str = m.Get<Expression>("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 => { AddIssue(binaryOperatorExpression, ctx.TranslateString("Use string.IsNullOrEmpty"), script => {
Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone()); Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone());
if (isNegated) if (isNegated)

5
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) public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration)
{ {
var addAccessor = eventDeclaration.AddAccessor; var addAccessor = eventDeclaration.AddAccessor;
FindIssuesInNode(addAccessor, addAccessor.Body, "add accessor");
var removeAccessor = eventDeclaration.RemoveAccessor; 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"); FindIssuesInNode(removeAccessor, removeAccessor.Body, "remove accessor");
} }

45
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableNotUsedIssues/ParameterNotUsedIssue.cs

@ -28,6 +28,8 @@ using ICSharpCode.NRefactory.Semantics;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp.Resolver;
using System;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -41,15 +43,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
#region ICodeIssueProvider implementation #region ICodeIssueProvider implementation
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context) public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{ {
return new GatherVisitor (context).GetIssues (); var delegateVisitor = new GetDelgateUsagesVisitor (context);
context.RootNode.AcceptVisitor (delegateVisitor);
return new GatherVisitor (context, delegateVisitor).GetIssues ();
} }
#endregion #endregion
// Collect all methods that are used as delegate
class GetDelgateUsagesVisitor : DepthFirstAstVisitor
{
BaseRefactoringContext ctx;
public readonly List<IMethod> UsedMethods = new List<IMethod> ();
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 class GatherVisitor : GatherVisitorBase
{ {
public GatherVisitor (BaseRefactoringContext ctx) GetDelgateUsagesVisitor usedDelegates;
public GatherVisitor (BaseRefactoringContext ctx, GetDelgateUsagesVisitor usedDelegates)
: base (ctx) : base (ctx)
{ {
this.usedDelegates = usedDelegates;
} }
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
@ -66,8 +101,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
if (member.ImplementedInterfaceMembers.Any ()) if (member.ImplementedInterfaceMembers.Any ())
return; return;
if (usedDelegates.UsedMethods.Any (m => m.Region.Begin == methodDeclaration.StartLocation))
base.VisitMethodDeclaration(methodDeclaration); return;
foreach (var parameter in methodDeclaration.Parameters)
parameter.AcceptVisitor (this);
} }
public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration) public override void VisitParameterDeclaration (ParameterDeclaration parameterDeclaration)

69
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/LocalVariableOnlyAssignedIssue.cs

@ -1,69 +0,0 @@
//
// LocalVariableOnlyAssignedIssue.cs
//
// Author:
// Mansheng Yang <lightyang0@gmail.com>
//
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using 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"));
}
}
}
}

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/ParameterOnlyAssignedIssue.cs

@ -28,7 +28,7 @@ using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
[IssueDescription ("Parameter is only assigned", [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, Category = IssueCategories.CodeQualityIssues,
Severity = Severity.Warning, Severity = Severity.Warning,
IssueMarker = IssueMarker.Underline)] IssueMarker = IssueMarker.Underline)]
@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return; return;
} }
AddIssue(parameterDeclaration.NameToken, 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"));
} }
} }
} }

5
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.Decrement:
case UnaryOperatorType.PostDecrement: case UnaryOperatorType.PostDecrement:
assignment = true; assignment = true;
if (!(parent.Parent is ExpressionStatement))
nonAssignment = true;
continue; continue;
} }
} else if (parent is DirectionExpression) { } else if (parent is DirectionExpression) {
if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) { if (((DirectionExpression)parent).FieldDirection == FieldDirection.Out) {
assignment = true; assignment = true;
// Using dummy variables is necessary for ignoring
// out-arguments, so we don't want to warn for those.
nonAssignment = true;
continue; continue;
} }
} }

13
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs

@ -17,8 +17,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring namespace ICSharpCode.NRefactory.CSharp.Refactoring
{ {
@ -95,14 +97,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return originalDocument.Version.MoveOffsetTo(currentDocument.Version, originalDocumentOffset); return originalDocument.Version.MoveOffsetTo(currentDocument.Version, originalDocumentOffset);
} }
public override void FormatText(AstNode node) public override void FormatText(IEnumerable<AstNode> nodes)
{ {
var segment = GetSegment(node);
var syntaxTree = SyntaxTree.Parse(currentDocument, "dummy.cs"); var syntaxTree = SyntaxTree.Parse(currentDocument, "dummy.cs");
foreach (var node in nodes.OrderByDescending (n => n.StartLocation)) {
var segment = GetSegment(node);
var formatter = new AstFormattingVisitor(FormattingOptions, currentDocument, Options); 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); syntaxTree.AcceptVisitor(formatter);
formatter.ApplyChanges(segment.Offset, segment.Length); formatter.ApplyChanges(segment.Offset, segment.Length);
} }
}
protected override int GetIndentLevelAt(int offset) protected override int GetIndentLevelAt(int offset)
{ {

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs

@ -202,20 +202,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
CorrectFormatting (node, node); CorrectFormatting (node, node);
} }
List<AstNode> nodesToFormat = new List<AstNode> ();
void CorrectFormatting(AstNode node, AstNode newNode) void CorrectFormatting(AstNode node, AstNode newNode)
{ {
if (node is Identifier || node is IdentifierExpression || node is CSharpTokenNode || node is AstType) if (node is Identifier || node is IdentifierExpression || node is CSharpTokenNode || node is AstType)
return; return;
if (node == null || node.Parent is BlockStatement) { if (node == null || node.Parent is BlockStatement) {
FormatText(newNode); nodesToFormat.Add (newNode);
} else { } 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 Remove (AstNode node, bool removeEmptyLine = true);
public abstract void FormatText (AstNode node); public abstract void FormatText (IEnumerable<AstNode> nodes);
public void FormatText (params AstNode[] node)
{
FormatText ((IEnumerable<AstNode>)node);
}
public virtual void Select (AstNode node) public virtual void Select (AstNode node)
{ {
@ -380,6 +387,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public virtual void Dispose() public virtual void Dispose()
{ {
FormatText (nodesToFormat);
} }
public enum NewTypeContext { public enum NewTypeContext {

128
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs

@ -1,128 +0,0 @@
//
// TypeCompatibilityHelper.cs
//
// Author:
// Mansheng Yang <lightyang0@gmail.com>
//
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System.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<IType> 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;
}
}
}

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -788,7 +788,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Find the candidate operators: // Find the candidate operators:
Predicate<IUnresolvedMethod> opFilter; Predicate<IUnresolvedMethod> opFilter;
if (isExplicit) 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 else
opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1; opFilter = m => m.IsStatic && m.IsOperator && m.Name == "op_Implicit" && m.Parameters.Count == 1;

4
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -2913,7 +2913,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foreach (VariableInitializer vi in variableDeclarationStatement.Variables) { foreach (VariableInitializer vi in variableDeclarationStatement.Variables) {
IVariable v; IVariable v;
if (isConst) { 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 { } else {
v = MakeVariable(type, vi.NameToken); v = MakeVariable(type, vi.NameToken);
} }

11
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertSwitchToIfTests.cs

@ -138,9 +138,14 @@ class TestClass
{ {
if (a == 0) { if (a == 0) {
int b = 1; 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 {
} }
} }
}"); }");

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/SplitDeclarationAndAssignmentTests.cs

@ -101,6 +101,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions
" {" + Environment.NewLine + " {" + Environment.NewLine +
" int i;" + Environment.NewLine + " int i;" + Environment.NewLine +
" for (i = 1; i < 10; i++) {" + Environment.NewLine + " for (i = 1; i < 10; i++) {" + Environment.NewLine +
" " + Environment.NewLine +
" }" + Environment.NewLine + " }" + Environment.NewLine +
" }" + Environment.NewLine + " }" + Environment.NewLine +
"}", result); "}", result);

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AssignmentMadeToSameVariableIssueTests.cs

@ -209,6 +209,20 @@ class TestClass
{ {
nested.nested.a = nested.nested.a; nested.nested.a = nested.nested.a;
} }
}";
Test<AssignmentMadeToSameVariableIssue> (input, 0);
}
[Test]
public void TestNoIssueWithCompoundOperator ()
{
var input = @"
class TestClass
{
void TestMethod (int a)
{
a += a;
}
}"; }";
Test<AssignmentMadeToSameVariableIssue> (input, 0); Test<AssignmentMadeToSameVariableIssue> (input, 0);
} }

34
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/CastExpressionOfIncompatibleTypeIssueTests.cs

@ -56,7 +56,39 @@ class TestClass
void TestMethod () void TestMethod ()
{ {
var x1 = (int)123; var x1 = (int)123;
var x2 = (int)System.ConsoleKey.A; var x2 = (short)123;
var x3 = (int)System.ConsoleKey.A;
}
}";
Test<CastExpressionOfIncompatibleTypeIssue> (input, 0);
}
[Test]
public void UnknownIdentifierDoesNotCauseIncompatibleCastIssue ()
{
var input = @"
class TestClass
{
void TestMethod ()
{
var x1 = unknown as string;
var x2 = (string)unknown;
}
}";
Test<CastExpressionOfIncompatibleTypeIssue> (input, 0);
}
[Test]
public void UnknownTargetTypeDoesNotCauseIncompatibleCastIssue ()
{
var input = @"
class TestClass
{
void TestMethod (int p)
{
var x1 = (unknown)p;
var x2 = p as unknown;
} }
}"; }";

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssueTests.cs

@ -90,5 +90,19 @@ class TestClass
}"; }";
Test<ExpressionIsAlwaysOfProvidedTypeIssue> (input, 1, output); Test<ExpressionIsAlwaysOfProvidedTypeIssue> (input, 1, output);
} }
[Test]
public void IntIsNotDouble ()
{
var input = @"
sealed class TestClass
{
void TestMethod (int x)
{
if (x is double) ;
}
}";
Test<ExpressionIsAlwaysOfProvidedTypeIssue> (input, 0);
}
} }
} }

72
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs

@ -92,6 +92,20 @@ class TestClass
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1);
} }
[Test]
public void TestObjectToInt ()
{
var input = @"
sealed class TestClass
{
void TestMethod (object x)
{
if (x is int) ;
}
}";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
}
[Test] [Test]
public void TestClassIsTypeParameter () public void TestClassIsTypeParameter ()
{ {
@ -153,7 +167,8 @@ class TestClass
if (x is T) ; if (x is T) ;
} }
}"; }";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1); // this is possible with T==object
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
} }
[Test] [Test]
@ -216,45 +231,72 @@ sealed class TestClass
} }
[Test] [Test]
public void TestTypeParameter5 () public void TestTypeParameterIsTypeParameter ()
{ {
var input = @" var input = @"
sealed class TestClass class TestClass2 { }
class TestClass
{ {
public TestClass (int i) { } void TestMethod<T, T2> (T x) where T : TestClass where T2 : TestClass2
void TestMethod<T> (T x) where T : new()
{ {
if (x is TestClass) ; if (x is T2) ;
} }
}"; }";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1);
} }
[Test] [Test]
public void TestTypeParameterIsTypeParameter () public void TestTypeParameterIsTypeParameter2 ()
{ {
var input = @" var input = @"
class TestClass2 { } interface ITest { }
class TestClass class TestClass
{ {
void TestMethod<T, T2> (T x) where T : TestClass where T2 : TestClass2 void TestMethod<T, T2> (T x) where T : TestClass where T2 : ITest, new()
{ {
if (x is T2) ; if (x is T2) ;
} }
}"; }";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
} }
[Test] [Test]
public void TestTypeParameterIsTypeParameter2 () public void TestObjectArrayToStringArray ()
{ {
var input = @" var input = @"
interface ITest { } sealed class TestClass
class TestClass
{ {
void TestMethod<T, T2> (T x) where T : TestClass where T2 : ITest, new() void TestMethod (object[] x)
{ {
if (x is T2) ; if (x is string[]) ;
}
}";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
}
[Test]
public void UnknownExpression()
{
var input = @"
sealed class TestClass
{
void TestMethod ()
{
if (unknown is string) ;
}
}";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
}
[Test]
public void UnknownType()
{
var input = @"
sealed class TestClass
{
void TestMethod (int x)
{
if (x is unknown) ;
} }
}"; }";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);

1
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 ArgumentException (""The parameter 'blah' can not be null"", ""blah"");
throw new ArgumentOutOfRangeException (""blah"", ""The parameter 'blah' can not be null""); throw new ArgumentOutOfRangeException (""blah"", ""The parameter 'blah' can not be null"");
throw new DuplicateWaitObjectException (""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; TestRefactoringContext context;

97
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/LocalVariableOnlyAssignedIssueTests.cs

@ -1,97 +0,0 @@
//
// LocalVariableOnlyAssignedIssueTests.cs
//
// Author:
// Mansheng Yang <lightyang0@gmail.com>
//
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using 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<LocalVariableOnlyAssignedIssue> (input1, 1);
var input2 = @"
class TestClass
{
void TestMethod()
{
int i;
i = 1;
}
}";
Test<LocalVariableOnlyAssignedIssue> (input2, 1);
}
[Test]
public void TestUsedValue ()
{
var input = @"
class TestClass
{
int TestMethod()
{
int i;
i = 1;
int j = i + 1;
return j;
}
}";
Test<LocalVariableOnlyAssignedIssue> (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<LocalVariableOnlyAssignedIssue> (input1, 1);
}
}
}

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodNeverReturnsIssueTests.cs

@ -87,5 +87,19 @@ class TestClass
}"; }";
Test<MethodNeverReturnsIssue> (input, 1); Test<MethodNeverReturnsIssue> (input, 1);
} }
[Test]
public void YieldBreak ()
{
var input = @"
class TestClass
{
System.Collections.Generic.IEnumerable<string> TestMethod ()
{
yield break;
}
}";
Test<MethodNeverReturnsIssue> (input, 0);
}
} }
} }

12
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) void TestMethod (int a, int b = 1, int c = 1)
{ } { }
}";
Test<MethodOverloadHidesOptionalParameterIssue> (input, 0);
}
[Test]
public void TestNoIssue_Generics ()
{
var input = @"
class TestClass
{
void TestMethod (object obj) { }
void TestMethod<T> (object obj, int arg = 0) { }
}"; }";
Test<MethodOverloadHidesOptionalParameterIssue> (input, 0); Test<MethodOverloadHidesOptionalParameterIssue> (input, 0);
} }

93
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MissingStringComparisonIssueTests.cs

@ -0,0 +1,93 @@
//
// Author:
// Daniel Grunwald <daniel@danielgrunwald.de>
//
// 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<string> 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<string> 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<MissingStringComparisonIssue>(stringIndexOfStringCalls, 4, stringIndexOfStringCallsWithComparison);
}
[Test]
public void IndexOfStringCallsAlreadyWithComparison()
{
Test<MissingStringComparisonIssue>(stringIndexOfStringCallsWithComparison, 0);
}
[Test]
public void StringIndexOfChar()
{
string program = @"using System;
class Test {
void M(string text) {
text.IndexOf('.');
}
}";
Test<MissingStringComparisonIssue>(program, 0);
}
[Test]
public void ListIndexOf()
{
string program = @"using System.Collections.Generic;
class Test {
void M(List<string> list) {
list.IndexOf("".com"");
}
}";
Test<MissingStringComparisonIssue>(program, 0);
}
}
}

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ParameterNotUsedIssueTests.cs

@ -114,5 +114,21 @@ class TestClass {
}"; }";
Test<ParameterNotUsedIssue> (input, 0); Test<ParameterNotUsedIssue> (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<ParameterNotUsedIssue> (input, 0);
}
} }
} }

23
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); var issues = GetIssues (new RedundantWhereWithPredicateIssue (), input, out context);
Assert.AreEqual (0, issues.Count); 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);
}
}");
}
} }
} }

22
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); var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context);
Assert.AreEqual(0, issues.Count); Assert.AreEqual(0, issues.Count);
} }
[Test]
public void IgnoresCuriouslyRecurringTemplatePattern()
{
var input = @"
class Base<T>
{
public static void F() { }
}
class Derived : Base<Derived> {}
class Test
{
void Main()
{
Derived.F();
}
}";
// do not suggest replacing 'Derived.F()' with 'Base<Derived>.F()'
TestRefactoringContext context;
var issues = GetIssues(new ReferenceToStaticMemberViaDerivedTypeIssue(), input, out context);
Assert.AreEqual(0, issues.Count);
}
} }
} }

18
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);
}
} }
} }

23
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ValueParameterUnusedTests.cs

@ -76,9 +76,11 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
var input = @"class A var input = @"class A
{ {
delegate void TestEventHandler (); delegate void TestEventHandler ();
TestEventHandler eventTested;
event TestEventHandler EventTested event TestEventHandler EventTested
{ {
add { add {
eventTested += value;
} }
remove { remove {
} }
@ -86,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
}"; }";
TestRefactoringContext context; TestRefactoringContext context;
var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context); var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context);
Assert.AreEqual(2, issues.Count); Assert.AreEqual(1, issues.Count);
} }
[Test] [Test]
@ -153,6 +155,25 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues
throw new Exception(); 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; TestRefactoringContext context;
var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context); var issues = GetIssues(new ValueParameterUnusedIssue(), input, out context);

31
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))); 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<MemberResolveResult>(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<LocalResolveResult>(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);
}
} }
} }

18
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

@ -490,6 +490,24 @@ class C {
Assert.AreEqual("B", rr.Input.Type.Name); Assert.AreEqual("B", rr.Input.Type.Name);
} }
[Test]
public void ImplicitUserDefinedConversionFollowedByExplicitNumericConversion()
{
var rr = Resolve<ConversionResolveResult>(@"
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] [Test]
[Ignore("Not implemented yet.")] [Ignore("Not implemented yet.")]
public void BothDirectConversionAndBaseClassConversionAvailable() public void BothDirectConversionAndBaseClassConversionAvailable()

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -110,9 +110,9 @@
<Compile Include="CSharp\CodeIssues\IdenticalConditionalBranchIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\IdenticalConditionalBranchIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\LocalVariableHidesMemberIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\LocalVariableHidesMemberIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\LocalVariableNotUsedIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\LocalVariableNotUsedIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\LocalVariableOnlyAssignedIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\MethodNeverReturnsIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\MethodNeverReturnsIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\MethodOverloadHidesOptionalParameterIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\MethodOverloadHidesOptionalParameterIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\MissingStringComparisonIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\MultipleEnumerationIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\MultipleEnumerationIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\NegativeRelationalExpressionIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\NegativeRelationalExpressionIssueTests.cs" />
<Compile Include="CSharp\CodeIssues\ParameterHidesMemberIssueTests.cs" /> <Compile Include="CSharp\CodeIssues\ParameterHidesMemberIssueTests.cs" />

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs

@ -107,7 +107,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary> /// <summary>
/// Gets the effective interface set of this type parameter. /// Gets the effective interface set of this type parameter.
/// </summary> /// </summary>
IList<IType> EffectiveInterfaceSet { get; } ICollection<IType> EffectiveInterfaceSet { get; }
/// <summary> /// <summary>
/// Gets if the type parameter has the 'new()' constraint. /// Gets if the type parameter has the 'new()' constraint.

43
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs

@ -94,19 +94,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IType EffectiveBaseClass { public IType EffectiveBaseClass {
get { get {
if (effectiveBaseClass == null) 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(); effectiveBaseClass = CalculateEffectiveBaseClass();
}
}
return effectiveBaseClass; return effectiveBaseClass;
} }
} }
IType CalculateEffectiveBaseClass() IType CalculateEffectiveBaseClass()
{ {
// protect against cyclic type parameters
using (var busyLock = BusyManager.Enter(this)) {
if (!busyLock.Success)
return SpecialType.UnknownType;
if (HasValueTypeConstraint) if (HasValueTypeConstraint)
return this.Compilation.FindType(KnownTypeCode.ValueType); return this.Compilation.FindType(KnownTypeCode.ValueType);
@ -130,13 +131,37 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
} }
return result; return result;
} }
}
public IList<IType> EffectiveInterfaceSet { ICollection<IType> effectiveInterfaceSet;
public ICollection<IType> EffectiveInterfaceSet {
get { 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<IType>.Instance; // don't cache this error
return LazyInit.GetOrSet(ref effectiveInterfaceSet, CalculateEffectiveInterfaceSet());
}
} }
} }
}
ICollection<IType> CalculateEffectiveInterfaceSet()
{
HashSet<IType> result = new HashSet<IType>();
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; } public abstract bool HasDefaultConstructorConstraint { get; }
public abstract bool HasReferenceTypeConstraint { get; } public abstract bool HasReferenceTypeConstraint { get; }

2
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs

@ -189,7 +189,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
get { return SpecialType.UnknownType; } get { return SpecialType.UnknownType; }
} }
IList<IType> ITypeParameter.EffectiveInterfaceSet { ICollection<IType> ITypeParameter.EffectiveInterfaceSet {
get { return EmptyList<IType>.Instance; } get { return EmptyList<IType>.Instance; }
} }

5
src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/KnownTypeCache.cs

@ -48,12 +48,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
KnownTypeReference typeRef = KnownTypeReference.Get(typeCode); KnownTypeReference typeRef = KnownTypeReference.Get(typeCode);
if (typeRef == null) if (typeRef == null)
return SpecialType.UnknownType; return SpecialType.UnknownType;
var typeName = new TopLevelTypeName(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount);
foreach (IAssembly asm in compilation.Assemblies) { 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) if (typeDef != null)
return typeDef; return typeDef;
} }
return new UnknownType(typeRef.Namespace, typeRef.Name, typeRef.TypeParameterCount); return new UnknownType(typeName);
} }
} }
} }

Loading…
Cancel
Save