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 @@ @@ -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; @@ -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 @@ -750,5 +751,57 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
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 @@ -78,6 +78,10 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
}
}
public IEnumerable<Statement> ReachableStatements {
get { return reachableStatements; }
}
public bool IsReachable(Statement statement)
{
return reachableStatements.Contains(statement);

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

@ -119,16 +119,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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,6 +408,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -404,6 +408,7 @@ namespace ICSharpCode.NRefactory.CSharp
void ForceSpace(int startOffset, int endOffset, bool forceSpace)
{
int lastNonWs = SearchLastNonWsChar(startOffset, endOffset);
if (lastNonWs >= 0)
AddChange(lastNonWs + 1, System.Math.Max(0, endOffset - lastNonWs - 1), forceSpace ? " " : "");
}
// void ForceSpacesAfter (AstNode n, bool forceSpaces)

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

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

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

@ -70,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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 @@ -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<T>
}

7
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/AccessToClosureIssues/AccessToClosureIssue.cs

@ -115,8 +115,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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);
}

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

@ -56,6 +56,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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;

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

@ -71,6 +71,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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"));

14
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/CompareFloatWithEqualityOperatorIssue.cs

@ -80,12 +80,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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 @@ -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");

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

@ -27,6 +27,7 @@ @@ -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 @@ -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 @@ -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 @@ -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);
}
}
}
}

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

@ -25,6 +25,10 @@ @@ -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,22 +46,46 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -42,22 +46,46 @@ 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)
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);
}
}
}
}

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

@ -63,8 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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)

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

@ -43,8 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -43,8 +43,6 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
class GatherVisitor : GatherVisitorBase
{
readonly ControlFlowGraphBuilder cfgBuilder = new ControlFlowGraphBuilder ();
public GatherVisitor(BaseRefactoringContext ctx)
: base (ctx)
{
@ -58,31 +56,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -58,31 +56,19 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (methodDeclaration.Body.IsNull)
return;
var cfg = cfgBuilder.BuildControlFlowGraph (methodDeclaration.Body, ctx.Resolver,
ctx.CancellationToken);
var stack = new Stack<ControlFlowNode> ();
var visitedNodes = new HashSet<ControlFlowNode> ();
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;
}
}
if (!hasReachableReturn && !reachability.IsEndpointReachable(methodDeclaration.Body)) {
AddIssue (methodDeclaration.NameToken,
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 @@ -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<IMethod> ()
var overloads = method.DeclaringType.GetMethods(m => m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count)
.ToArray ();
var parameterNodes = methodDeclaration.Parameters.ToArray();

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

@ -0,0 +1,106 @@ @@ -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; @@ -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)]
@ -19,7 +19,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -19,7 +19,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
new InvocationExpression (
new MemberReferenceExpression (new AnyNode ("target"), "Where"),
new AnyNode ())),
"Any"));
Pattern.AnyString));
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context)
{
@ -41,11 +41,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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<InvocationExpression> ("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,12 +53,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -53,12 +53,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (predResolve.Type.TypeParameterCount != 2)
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 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 @@ -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 @@ -96,14 +102,31 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
IEnumerable<CodeAction> 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
}

58
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ResultOfAsyncCallShouldNotBeIgnoredIssue.cs

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

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

@ -62,8 +62,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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");
}

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

@ -28,6 +28,8 @@ using ICSharpCode.NRefactory.Semantics; @@ -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 @@ -41,15 +43,48 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
#region ICodeIssueProvider implementation
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
// 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
{
public GatherVisitor (BaseRefactoringContext ctx)
GetDelgateUsagesVisitor usedDelegates;
public GatherVisitor (BaseRefactoringContext ctx, GetDelgateUsagesVisitor usedDelegates)
: base (ctx)
{
this.usedDelegates = usedDelegates;
}
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
@ -66,8 +101,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -66,8 +101,10 @@ 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)

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

@ -1,69 +0,0 @@ @@ -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; @@ -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 @@ -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"));
}
}
}

5
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/VariableOnlyAssignedIssues/VariableOnlyAssignedIssue.cs

@ -66,11 +66,16 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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;
}
}

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

@ -17,8 +17,10 @@ @@ -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,14 +97,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -95,14 +97,21 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
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");
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)
{

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

@ -202,20 +202,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -202,20 +202,27 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
CorrectFormatting (node, node);
}
List<AstNode> nodesToFormat = new List<AstNode> ();
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<AstNode> nodes);
public void FormatText (params AstNode[] node)
{
FormatText ((IEnumerable<AstNode>)node);
}
public virtual void Select (AstNode node)
{
@ -380,6 +387,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -380,6 +387,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public virtual void Dispose()
{
FormatText (nodesToFormat);
}
public enum NewTypeContext {

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

@ -1,128 +0,0 @@ @@ -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 @@ -788,7 +788,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Find the candidate operators:
Predicate<IUnresolvedMethod> 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;

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

@ -2913,7 +2913,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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);
}

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

@ -138,9 +138,14 @@ class TestClass @@ -138,9 +138,14 @@ 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 {
}
}
}");

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

@ -101,6 +101,7 @@ namespace ICSharpCode.NRefactory.CSharp.CodeActions @@ -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);

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

@ -209,6 +209,20 @@ class TestClass @@ -209,6 +209,20 @@ class TestClass
{
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);
}

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

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

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/IncorrectExceptionParameterOrderingTests.cs

@ -79,6 +79,7 @@ class A @@ -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;

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

@ -1,97 +0,0 @@ @@ -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 @@ -87,5 +87,19 @@ class TestClass
}";
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 @@ -68,6 +68,18 @@ class TestClass
{
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);
}

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

@ -0,0 +1,93 @@ @@ -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 { @@ -114,5 +114,21 @@ class TestClass {
}";
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 @@ -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);
}
}");
}
}
}

22
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ReferenceToStaticMemberViaDerivedTypeTests.cs

@ -299,6 +299,28 @@ class B : A @@ -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<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 @@ -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 @@ -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 @@ -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 @@ -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);

31
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs

@ -97,5 +97,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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<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 { @@ -490,6 +490,24 @@ class C {
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]
[Ignore("Not implemented yet.")]
public void BothDirectConversionAndBaseClassConversionAvailable()

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

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

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

@ -107,7 +107,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -107,7 +107,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// <summary>
/// Gets the effective interface set of this type parameter.
/// </summary>
IList<IType> EffectiveInterfaceSet { get; }
ICollection<IType> EffectiveInterfaceSet { get; }
/// <summary>
/// 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 @@ -94,19 +94,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
public IType EffectiveBaseClass {
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();
}
}
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);
@ -130,13 +131,37 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -130,13 +131,37 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
}
return result;
}
}
public IList<IType> EffectiveInterfaceSet {
ICollection<IType> effectiveInterfaceSet;
public ICollection<IType> 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<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 HasReferenceTypeConstraint { get; }

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

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

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

@ -48,12 +48,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -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);
}
}
}

Loading…
Cancel
Save