Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: d37a7ba16d
Fetching contributors…

Cannot retrieve contributors at this time

255 lines (237 sloc) 9.924 kb
// 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;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.ConsistencyCheck
{
public class RandomizedOrderResolverTest
{
static Random sharedRnd = new Random();
CSharpAstResolver resolver;
CSharpAstResolver resolveAllResolver;
public static void RunTest(CSharpFile file)
{
int seed;
lock (sharedRnd) {
seed = sharedRnd.Next();
}
Random rnd = new Random(seed);
var test = new RandomizedOrderResolverTest();
// Resolve all nodes, but in a random order without using a navigator.
test.resolver = new CSharpAstResolver(file.Project.Compilation, file.SyntaxTree, file.UnresolvedTypeSystemForFile);
// For comparing whether the results are equivalent, we also use a normal 'resolve all' resolver:
test.resolveAllResolver = new CSharpAstResolver(file.Project.Compilation, file.SyntaxTree, file.UnresolvedTypeSystemForFile);
test.resolveAllResolver.ApplyNavigator(new ResolveAllNavigator(), CancellationToken.None);
// Prepare list of actions that we need to verify:
var actions = new List<Func<bool>>();
bool checkResults = rnd.Next(0, 2) == 0;
bool checkStateBefore = rnd.Next(0, 2) == 0;
bool checkStateAfter = rnd.Next(0, 2) == 0;
bool checkConversion = rnd.Next(0, 2) == 0;
bool checkExpectedType = rnd.Next(0, 2) == 0;
foreach (var _node in file.SyntaxTree.DescendantsAndSelf) {
var node = _node;
if (CSharpAstResolver.IsUnresolvableNode(node))
continue;
if (checkResults)
actions.Add(() => test.CheckResult(node));
if (checkStateBefore)
actions.Add(() => test.CheckStateBefore(node));
if (checkStateAfter)
actions.Add(() => test.CheckStateAfter(node));
var expr = node as Expression;
if (expr != null) {
if (checkConversion)
actions.Add(() => test.CheckConversion(expr));
if (checkExpectedType)
actions.Add(() => test.CheckExpectedType(expr));
}
}
// Fisher-Yates shuffle
for (int i = actions.Count - 1; i > 0; i--) {
int j = rnd.Next(0, i);
var tmp = actions[i];
actions[i] = actions[j];
actions[j] = tmp;
}
foreach (var action in actions) {
if (!action()) {
Console.WriteLine("Seed for this file was: " + seed);
break;
}
}
}
bool CheckResult(AstNode node)
{
ResolveResult expectedResult = resolveAllResolver.Resolve(node);
ResolveResult actualResult = resolver.Resolve(node);
if (IsEqualResolveResult(expectedResult, actualResult))
return true;
Console.WriteLine("Different resolve results for '{0}' at {1} in {2}:", node, node.StartLocation, node.GetRegion().FileName);
Console.WriteLine(" expected: " + expectedResult);
Console.WriteLine(" actual: " + actualResult);
return false;
}
bool CheckStateBefore(AstNode node)
{
var expectedState = resolveAllResolver.GetResolverStateBefore(node);
var actualState = resolver.GetResolverStateBefore(node);
if (IsEqualResolverState(expectedState, actualState))
return true;
Console.WriteLine("Different resolver states before '{0}' at {1} in {2}.", node, node.StartLocation, node.GetRegion().FileName);
return false;
}
bool CheckStateAfter(AstNode node)
{
var expectedState = resolveAllResolver.GetResolverStateAfter(node);
var actualState = resolver.GetResolverStateAfter(node);
if (IsEqualResolverState(expectedState, actualState))
return true;
Console.WriteLine("Different resolver states after '{0}' at {1} in {2}.", node, node.StartLocation, node.GetRegion().FileName);
return false;
}
bool CheckConversion(Expression node)
{
Conversion expectedConversion = resolveAllResolver.GetConversion(node);
Conversion actualConversion = resolver.GetConversion(node);
if (Compare(expectedConversion, actualConversion, typeof(Conversion)))
return true;
Console.WriteLine("Different conversions for '{0}' at {1} in {2}:", node, node.StartLocation, node.GetRegion().FileName);
Console.WriteLine(" expected: " + expectedConversion);
Console.WriteLine(" actual: " + actualConversion);
return false;
}
bool CheckExpectedType(Expression node)
{
IType expectedExpectedType = resolveAllResolver.GetExpectedType(node);
IType actualExpectedType = resolver.GetExpectedType(node);
if (expectedExpectedType.Equals(actualExpectedType))
return true;
Console.WriteLine("Different expected types for '{0}' at {1} in {2}:", node, node.StartLocation, node.GetRegion().FileName);
Console.WriteLine(" expected: " + expectedExpectedType);
Console.WriteLine(" actual: " + actualExpectedType);
return false;
}
internal static bool IsEqualResolveResult(ResolveResult rr1, ResolveResult rr2)
{
if (rr1 == rr2)
return true;
if (rr1 == null || rr2 == null)
return false;
if (rr1.GetType() != rr2.GetType())
return false;
bool eq = true;
foreach (var property in rr1.GetType().GetProperties()) {
object val1 = property.GetValue(rr1, null);
object val2 = property.GetValue(rr2, null);
eq &= Compare(val1, val2, property.PropertyType);
}
foreach (var field in rr1.GetType().GetFields()) {
object val1 = field.GetValue(rr1);
object val2 = field.GetValue(rr2);
eq &= Compare(val1, val2, field.FieldType);
}
return eq;
}
static bool Compare(object val1, object val2, Type type)
{
if (val1 == val2)
return true;
if (val1 == null || val2 == null)
return false;
if (type == typeof(ResolveResult)) {
return IsEqualResolveResult((ResolveResult)val1, (ResolveResult)val2);
} else if (type == typeof(IVariable) || type == typeof(IParameter)) {
return IsEqualVariable((IVariable)val1, (IVariable)val2);
} else if (type == typeof(MethodListWithDeclaringType)) {
var l1 = (MethodListWithDeclaringType)val1;
var l2 = (MethodListWithDeclaringType)val2;
return object.Equals(l1.DeclaringType, l2.DeclaringType)
&& Compare(l1, l2, type.BaseType);
} else if (type.IsArray || type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>) || type.GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>) || type.GetGenericTypeDefinition() == typeof(IList<>) || type.GetGenericTypeDefinition() == typeof(ICollection<>) || type.GetGenericTypeDefinition() == typeof(IEnumerable<>))) {
Type elementType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0];
object[] arr1 = ((IEnumerable)val1).Cast<object>().ToArray();
object[] arr2 = ((IEnumerable)val2).Cast<object>().ToArray();
if (arr1.Length != arr2.Length)
return false;
for (int i = 0; i < arr1.Length; i++) {
if (!Compare(arr1[i], arr2[i], elementType))
return false;
}
return true;
} else {
if (object.Equals(val1, val2))
return true;
else if (val1 is Conversion && val2 is Conversion && ((Conversion)val1).IsAnonymousFunctionConversion && ((Conversion)val2).IsAnonymousFunctionConversion)
return true;
else
return false;
}
}
internal static bool IsEqualResolverState(CSharpResolver r1, CSharpResolver r2)
{
if (r1.CheckForOverflow != r2.CheckForOverflow)
return false;
if (r1.Compilation != r2.Compilation)
return false;
if (!object.Equals(r1.CurrentMember, r2.CurrentMember))
return false;
if (!object.Equals(r1.CurrentObjectInitializerType, r2.CurrentObjectInitializerType))
return false;
if (!object.Equals(r1.CurrentTypeDefinition, r2.CurrentTypeDefinition))
return false;
if (!object.Equals(r1.CurrentUsingScope, r2.CurrentUsingScope))
return false;
if (r1.IsWithinLambdaExpression != r2.IsWithinLambdaExpression)
return false;
if (r1.LocalVariables.Count() != r2.LocalVariables.Count())
return false;
return r1.LocalVariables.Zip(r2.LocalVariables, IsEqualVariable).All(_ => _);
}
internal static bool IsEqualVariable(IVariable v1, IVariable v2)
{
return object.Equals(v1.ConstantValue, v2.ConstantValue)
&& v1.IsConst == v2.IsConst
&& v1.Name == v2.Name
&& v1.Region == v2.Region
&& object.Equals(v1.Type, v2.Type);
}
sealed class ResolveAllNavigator : IResolveVisitorNavigator
{
public ResolveVisitorNavigationMode Scan(AstNode node)
{
return ResolveVisitorNavigationMode.Resolve;
}
public void Resolved(AstNode node, ResolveResult result)
{
}
public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
}
}
}
}
Jump to Line
Something went wrong with that request. Please try again.