Browse Source

Simplified ExpressionIsNeverOfProvidedTypeIssue and fixed false positive when converting from System.Object to value types.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
e62e9469a7
  1. 3
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 8
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs
  3. 32
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsNeverOfProvidedTypeIssue.cs
  4. 128
      ICSharpCode.NRefactory.CSharp/Refactoring/TypeCompatibilityHelper.cs
  5. 46
      ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ExpressionIsNeverOfProvidedTypeIssueTests.cs

3
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -333,7 +333,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" />
@ -536,4 +535,4 @@
<ItemGroup> <ItemGroup>
<None Include="Parser\mcs\cs-parser.jay" /> <None Include="Parser\mcs\cs-parser.jay" />
</ItemGroup> </ItemGroup>
</Project> </Project>

8
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ExpressionIsAlwaysOfProvidedTypeIssue.cs

@ -44,11 +44,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 +58,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 (!foundConversion.IsValid)
return; return;
var action = new CodeAction (ctx.TranslateString ("Compare with 'null'"), var action = new CodeAction (ctx.TranslateString ("Compare with 'null'"),

32
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,21 +46,43 @@ 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 (IsValidReferenceOrBoxingConversion(exprType, providedType))
TypeCompatibilityHelper.TypeCompatiblity.NeverOfProvidedType) return;
AddIssue (isExpression, ctx.TranslateString ("Given expression is never of the provided type"));
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);
} }
} }
} }

128
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;
}
}
}

46
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]
@ -215,21 +230,6 @@ sealed class TestClass
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1);
} }
[Test]
public void TestTypeParameter5 ()
{
var input = @"
sealed class TestClass
{
public TestClass (int i) { }
void TestMethod<T> (T x) where T : new()
{
if (x is TestClass) ;
}
}";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 1);
}
[Test] [Test]
public void TestTypeParameterIsTypeParameter () public void TestTypeParameterIsTypeParameter ()
{ {
@ -256,6 +256,20 @@ class TestClass
{ {
if (x is T2) ; if (x is T2) ;
} }
}";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
}
[Test]
public void TestObjectArrayToStringArray ()
{
var input = @"
sealed class TestClass
{
void TestMethod (object[] x)
{
if (x is string[]) ;
}
}"; }";
Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0); Test<ExpressionIsNeverOfProvidedTypeIssue> (input, 0);
} }

Loading…
Cancel
Save