Browse Source

Fixed the ResolveVisitor scanning logic and several related issues.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
3d21a80e7d
  1. 16
      ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  2. 26
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  3. 12
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  4. 45
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
  5. 10
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  6. 56
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveAtLocation.cs
  7. 890
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  8. 1
      ICSharpCode.NRefactory.ConsistencyCheck/ICSharpCode.NRefactory.ConsistencyCheck.csproj
  9. 6
      ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
  10. 203
      ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs
  11. 3
      ICSharpCode.NRefactory.ConsistencyCheck/Readme.txt
  12. 32
      ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
  13. 23
      ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs
  14. 18
      ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs
  15. 10
      ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs
  16. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs
  17. 27
      ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs
  18. 18
      ICSharpCode.NRefactory/TypeSystem/PointerType.cs

16
ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -135,6 +135,18 @@ namespace ICSharpCode.NRefactory.CSharp @@ -135,6 +135,18 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
/// <summary>
/// Gets the region from StartLocation to EndLocation for this node.
/// The file name of the region is set based on the parent CompilationUnit's file name.
/// If this node is not connected to a whole compilation, the file name will be null.
/// </summary>
public ICSharpCode.NRefactory.TypeSystem.DomRegion GetRegion()
{
var cu = (this.Ancestors.LastOrDefault() ?? this) as CompilationUnit;
string fileName = (cu != null ? cu.FileName : null);
return new ICSharpCode.NRefactory.TypeSystem.DomRegion(fileName, this.StartLocation, this.EndLocation);
}
public AstNode Parent {
get { return parent; }
}
@ -537,7 +549,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -537,7 +549,7 @@ namespace ICSharpCode.NRefactory.CSharp
}
/// <summary>
/// Gets the node specified by T at location. This is useful for getting a specific node from the tree. For example searching
/// Gets the node specified by T at location. This is useful for getting a specific node from the tree. For example searching
/// the current method declaration.
/// </summary>
public T GetNodeAt<T> (TextLocation location) where T : AstNode
@ -579,7 +591,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -579,7 +591,7 @@ namespace ICSharpCode.NRefactory.CSharp
yield return node;
} else {
if (node.EndLocation <= start) {
next = node.NextSibling;
next = node.NextSibling;
} else {
next = node.FirstChild;
}

26
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs

@ -65,6 +65,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -65,6 +65,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
throw new ArgumentNullException ("factory");
this.document = document;
this.factory = factory;
// Set defaults for additional input properties
this.FormattingPolicy = new CSharpFormattingOptions();
this.EolMarker = Environment.NewLine;
this.IndentString = "\t";
}
public IEnumerable<ICompletionData> GetCompletionData (int offset, bool controlSpace)
@ -593,17 +597,16 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -593,17 +597,16 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
nodes.Add (n);
if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute)
nodes.Add (n.Parent);
var navigator = new NodeListResolveVisitorNavigator (nodes);
var visitor = new ResolveVisitor (csResolver, identifierStart.Item1, navigator);
visitor.Scan (identifierStart.Item3);
var astResolver = new CSharpAstResolver (csResolver, identifierStart.Item3, identifierStart.Item1);
astResolver.ApplyNavigator (new NodeListResolveVisitorNavigator (nodes));
try {
csResolver = visitor.GetResolverStateBefore (n);
csResolver = astResolver.GetResolverStateBefore (n);
} catch (Exception) {
csResolver = GetState ();
}
// add attribute properties.
if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute) {
var resolved = visitor.GetResolveResult (n.Parent);
var resolved = astResolver.Resolve (n.Parent);
if (resolved != null && resolved.Type != null) {
foreach (var property in resolved.Type.GetProperties (p => p.Accessibility == Accessibility.Public)) {
contextList.AddMember (property);
@ -797,17 +800,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -797,17 +800,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (csResolver == null) {
if (node != null) {
csResolver = GetState ();
var nodes = new List<AstNode> ();
var n = node;
nodes.Add (n);
if (n.Parent is ICSharpCode.NRefactory.CSharp.Attribute)
nodes.Add (n.Parent);
var navigator = new NodeListResolveVisitorNavigator (nodes);
var visitor = new ResolveVisitor (csResolver, xp != null ? xp.Item1 : CSharpParsedFile, navigator);
visitor.Scan (node);
//var astResolver = new CSharpAstResolver (csResolver, node, xp != null ? xp.Item1 : CSharpParsedFile);
try {
csResolver = visitor.GetResolverStateBefore (node);
//csResolver = astResolver.GetResolverStateBefore (node);
Console.WriteLine (csResolver.LocalVariables.Count ());
} catch (Exception e) {
Console.WriteLine ("E!!!" + e);
@ -849,7 +845,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -849,7 +845,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
Predicate<IType> typePred = null;
if (node is Attribute) {
var attribute = Compilation.FindType (typeof(System.Attribute));
var attribute = Compilation.FindType (KnownTypeCode.Attribute);
typePred = t => {
return t.GetAllBaseTypeDefinitions ().Any (bt => bt.Equals (attribute));
};

12
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// CSharpCompletionEngineBase.cs
//
// Author:
@ -472,14 +472,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -472,14 +472,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
// var newContent = ProjectContent.UpdateProjectContent (CSharpParsedFile, file);
var csResolver = new CSharpResolver (ctx);
var navigator = new NodeListResolveVisitorNavigator (new[] { resolveNode });
var visitor = new ResolveVisitor (csResolver, CSharpParsedFile, navigator);
var csResolver = new CSharpAstResolver(new CSharpResolver (ctx), unit, CSharpParsedFile);
visitor.Scan (unit);
var state = visitor.GetResolverStateBefore (resolveNode);
var result = visitor.GetResolveResult (resolveNode);
var result = csResolver.Resolve (resolveNode);
var state = csResolver.GetResolverStateBefore (resolveNode);
return Tuple.Create (result, state);
}

45
ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs

@ -33,7 +33,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -33,7 +33,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
readonly CSharpResolver initialResolverState;
readonly AstNode rootNode;
readonly CSharpParsedFile parsedFile;
ResolveVisitor resolveVisitor;
readonly ResolveVisitor resolveVisitor;
bool resolverInitialized;
/// <summary>
/// Creates a new C# AST resolver.
@ -54,6 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -54,6 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.initialResolverState = new CSharpResolver(compilation);
this.rootNode = compilationUnit;
this.parsedFile = parsedFile;
this.resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile);
}
/// <summary>
@ -73,6 +75,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -73,6 +75,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.initialResolverState = resolver;
this.rootNode = rootNode;
this.parsedFile = parsedFile;
this.resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile);
}
/// <summary>
@ -92,11 +95,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -92,11 +95,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (navigator == null)
throw new ArgumentNullException("navigator");
if (resolveVisitor != null)
throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver.");
resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile, navigator);
lock (resolveVisitor)
lock (resolveVisitor) {
if (resolverInitialized)
throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver.");
resolverInitialized = true;
resolveVisitor.SetNavigator(navigator);
resolveVisitor.Scan(rootNode);
resolveVisitor.SetNavigator(null);
}
}
/// <summary>
@ -106,18 +114,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -106,18 +114,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (node == null || node.IsNull)
return ErrorResolveResult.UnknownError;
InitResolver(node);
lock (resolveVisitor) {
InitResolver();
ResolveResult rr = resolveVisitor.GetResolveResult(node);
Debug.Assert(rr != null);
Debug.Assert(rr != null || IsUnresolvableNode(node));
return rr;
}
}
void InitResolver(AstNode firstNodeToResolve)
void InitResolver()
{
if (resolveVisitor == null) {
resolveVisitor = new ResolveVisitor(initialResolverState, parsedFile, new NodeListResolveVisitorNavigator(firstNodeToResolve));
if (!resolverInitialized) {
resolverInitialized = true;
resolveVisitor.Scan(rootNode);
}
}
@ -126,8 +134,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -126,8 +134,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (node == null || node.IsNull)
throw new ArgumentNullException("node");
InitResolver(node);
lock (resolveVisitor) {
InitResolver();
CSharpResolver resolver = resolveVisitor.GetResolverStateBefore(node);
Debug.Assert(resolver != null);
return resolver;
@ -141,8 +149,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -141,8 +149,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (expr == null || expr.IsNull)
throw new ArgumentNullException("expr");
InitResolver(expr);
lock (resolveVisitor) {
InitResolver();
return resolveVisitor.GetConversionWithTargetType(expr).TargetType;
}
}
@ -154,8 +162,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -154,8 +162,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (expr == null || expr.IsNull)
throw new ArgumentNullException("expr");
InitResolver(expr);
lock (resolveVisitor) {
InitResolver();
return resolveVisitor.GetConversionWithTargetType(expr).Conversion;
}
}
@ -165,6 +173,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -165,6 +173,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
public static bool IsUnresolvableNode(AstNode node)
{
if (node == null)
throw new ArgumentNullException("node");
if (node.NodeType == NodeType.Token) {
// Most tokens cannot be resolved, but there are a couple of special cases:
if (node.Parent is QueryClause && node is Identifier) {
return false;
} else if (node.Role == AstNode.Roles.Identifier) {
return !(node.Parent is ForeachStatement || node.Parent is CatchClause);
}
return true;
}
return (node.NodeType == NodeType.Whitespace || node is ArraySpecifier || node is NamedArgumentExpression);
}
}

10
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -252,6 +252,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -252,6 +252,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return WithLocalVariableStack(localVariableStack.Push(variable));
}
/// <summary>
/// Removes the variable that was just added.
/// </summary>
public CSharpResolver PopLastVariable()
{
if (localVariableStack.Peek() == null)
throw new InvalidOperationException("There is no variable within the current block.");
return WithLocalVariableStack(localVariableStack.Pop());
}
/// <summary>
/// Gets all currently visible local variables and lambda parameters.
/// </summary>

56
ICSharpCode.NRefactory.CSharp/Resolver/ResolveAtLocation.cs

@ -36,55 +36,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -36,55 +36,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AstNode node = cu.GetNodeAt(location);
if (node == null)
return null;
AstNode resolvableNode;
if (node is AstType) {
resolvableNode = node;
if (resolvableNode.Parent is ComposedType) {
while (resolvableNode.Parent is ComposedType)
resolvableNode = resolvableNode.Parent;
//node is preffered over the resolvable node. Which shouldn't be done in the case of nullables, arrays etc.
node = resolvableNode;
}
} else if (node is Identifier) {
resolvableNode = node.Parent;
} else if (node.NodeType == NodeType.Token) {
if (node.Parent is ConstructorInitializer) {
resolvableNode = node.Parent;
if (CSharpAstResolver.IsUnresolvableNode(node)) {
if (node is Identifier) {
node = node.Parent;
} else if (node.NodeType == NodeType.Token) {
if (node.Parent is ConstructorInitializer) {
node = node.Parent;
} else {
return null;
}
} else {
// don't resolve arbitrary nodes - we don't want to show tooltips for everything
return null;
}
} else {
// don't resolve arbitrary nodes - we don't want to show tooltips for everything
return null;
}
if (node == null)
return null;
if (resolvableNode != null && resolvableNode.Parent is ObjectCreateExpression) {
var parent = resolvableNode.Parent as ObjectCreateExpression;
if (resolvableNode == parent.Type)
resolvableNode = parent;
if (node.Parent is ObjectCreateExpression && node.Role == ObjectCreateExpression.Roles.Type) {
node = node.Parent;
}
InvocationExpression parentInvocation = null;
if ((resolvableNode is IdentifierExpression || resolvableNode is MemberReferenceExpression || resolvableNode is PointerReferenceExpression)) {
if (node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) {
// we also need to resolve the invocation
parentInvocation = resolvableNode.Parent as InvocationExpression;
parentInvocation = node.Parent as InvocationExpression;
}
IResolveVisitorNavigator navigator;
if (parentInvocation != null)
navigator = new NodeListResolveVisitorNavigator(new[] { resolvableNode, parentInvocation });
else
navigator = new NodeListResolveVisitorNavigator(new[] { resolvableNode });
CSharpResolver resolver = new CSharpResolver(compilation);
ResolveVisitor v = new ResolveVisitor(resolver, parsedFile, navigator);
v.Scan(cu);
// Prefer the RR from the token itself, if it was assigned a ResolveResult
// (this can happen with the identifiers in various nodes such as catch clauses or foreach statements)
ResolveResult rr = v.GetResolveResult(node) ?? v.GetResolveResult(resolvableNode);
CSharpAstResolver resolver = new CSharpAstResolver(compilation, cu, parsedFile);
ResolveResult rr = resolver.Resolve(node, cancellationToken);
if (rr is MethodGroupResolveResult && parentInvocation != null)
return v.GetResolveResult(parentInvocation);
return resolver.Resolve(parentInvocation);
else
return rr;
}

890
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

File diff suppressed because it is too large Load Diff

1
ICSharpCode.NRefactory.ConsistencyCheck/ICSharpCode.NRefactory.ConsistencyCheck.csproj

@ -50,6 +50,7 @@ @@ -50,6 +50,7 @@
<Compile Include="CSharpProject.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RandomizedOrderResolverTest.cs" />
<Compile Include="ResolverTest.cs" />
<Compile Include="RoundtripTest.cs" />
<Compile Include="Solution.cs" />

6
ICSharpCode.NRefactory.ConsistencyCheck/Program.cs

@ -32,6 +32,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -32,6 +32,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0",
@"C:\Program Files (x86)\GtkSharp\2.12\lib\gtk-sharp-2.0",
@"C:\Program Files (x86)\GtkSharp\2.12\lib\Mono.Posix",
@"C:\work\SD\src\Tools\NUnit"
};
public const string TempPath = @"C:\temp";
@ -50,8 +51,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -50,8 +51,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
solution.AllFiles.Count(),
solution.Projects.Count);
RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
//RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);
//RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);
RunTestOnAllFiles("Resolver test (randomized order)", RandomizedOrderResolverTest.RunTest);
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);

203
ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs

@ -0,0 +1,203 @@ @@ -0,0 +1,203 @@
// 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.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 rnd = new Random();
CSharpAstResolver resolver;
CSharpAstResolver resolveAllResolver;
public static void RunTest(CSharpFile file)
{
var test = new RandomizedOrderResolverTest();
// Resolve all nodes, but in a random order without using a navigator.
test.resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
// For comparing whether the results are equivalent, we also use a normal 'resolve all' resolver:
test.resolveAllResolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
test.resolveAllResolver.ApplyNavigator(new ResolveAllNavigator(), CancellationToken.None);
// Prepare list of actions that we need to verify:
var actions = new List<Func<bool>>();
foreach (var _node in file.CompilationUnit.DescendantsAndSelf) {
var node = _node;
if (CSharpAstResolver.IsUnresolvableNode(node))
continue;
//actions.Add(() => test.CheckResult(node));
actions.Add(() => test.CheckState(node));
var expr = node as Expression;
if (expr != null) {
//actions.Add(() => test.CheckExpectedType(node));
//actions.Add(() => test.CheckConversion(node));
}
}
/*
// 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())
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 CheckState(AstNode node)
{
var expectedState = resolveAllResolver.GetResolverStateBefore(node);
var actualState = resolver.GetResolverStateBefore(node);
if (IsEqualResolverState(expectedState, actualState))
return true;
Console.WriteLine("Different resolver states for '{0}' at {1} in {2}.", node, node.StartLocation, node.GetRegion().FileName);
return false;
}
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;
}
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(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;
}
}
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(_ => _);
}
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)
{
}
}
}
}

3
ICSharpCode.NRefactory.ConsistencyCheck/Readme.txt

@ -5,4 +5,5 @@ These checks assume that the code is valid C# without any compilation errors, @@ -5,4 +5,5 @@ These checks assume that the code is valid C# without any compilation errors,
so make sure to only pass in compilable source code.
Checks currently being performed:
-
- Roundtripping test: parses C# code and outputs it again using CSharpOutputVisitor, checking that only whitespace is changing
- ResolverTest: fully resolves all ASTs and validates that no errors are detected (no false positives in semantic error checking)

32
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -1,11 +1,21 @@ @@ -1,11 +1,21 @@
/*
* Created by SharpDevelop.
* User: Daniel
* Date: 12/9/2011
* Time: 01:26
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
// 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 System.Linq;
@ -71,10 +81,8 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -71,10 +81,8 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
public void Validate(CompilationUnit cu)
{
foreach (AstNode node in cu.DescendantsAndSelf.Except(resolvedNodes)) {
if (node.NodeType != NodeType.Token) {
if (!CSharpAstResolver.IsUnresolvableNode(node)) {
Console.WriteLine("Forgot to resolve " + node);
}
if (!CSharpAstResolver.IsUnresolvableNode(node)) {
Console.WriteLine("Forgot to resolve " + node);
}
}
}

23
ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs

@ -58,6 +58,17 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -58,6 +58,17 @@ namespace ICSharpCode.NRefactory.TypeSystem
IType IEntity.DeclaringType {
get { return declaringType; }
}
public override bool Equals(object obj)
{
AnonymousTypeProperty p = obj as AnonymousTypeProperty;
return p != null && declaringType.Equals(p.declaringType) && this.Name == p.Name;
}
public override int GetHashCode()
{
return declaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode());
}
}
public override ITypeReference ToTypeReference()
@ -105,6 +116,18 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -105,6 +116,18 @@ namespace ICSharpCode.NRefactory.TypeSystem
}
}
public override int GetHashCode()
{
unchecked {
int hashCode = resolvedProperties.Count;
foreach (var p in resolvedProperties) {
hashCode *= 31;
hashCode += p.Name.GetHashCode() ^ p.ReturnType.GetHashCode();
}
return hashCode;
}
}
public override bool Equals(IType other)
{
AnonymousType o = other as AnonymousType;

18
ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs

@ -21,7 +21,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -21,7 +21,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
public sealed class ByReferenceType : TypeWithElementType, ISupportsInterning
public sealed class ByReferenceType : TypeWithElementType
{
public ByReferenceType(IType elementType) : base(elementType)
{
@ -70,22 +70,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -70,22 +70,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
{
return new ByReferenceTypeReference(elementType.ToTypeReference());
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return GetHashCode();
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ByReferenceType brt = other as ByReferenceType;
return brt != null && this.elementType == brt.elementType;
}
}
[Serializable]

10
ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedTypeParameter.cs

@ -247,12 +247,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -247,12 +247,20 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
return m;
}
static IMethod GetDummyConstructor(ICompilation compilation)
{
// Reuse the same IMethod instance for all dummy constructors
// so that two occurrences of 'new T()' refer to the same constructor.
return (IMethod)compilation.CacheManager.GetOrAddShared(
dummyConstructor, _ => dummyConstructor.CreateResolved(compilation.TypeResolveContext));
}
public IEnumerable<IMethod> GetConstructors(Predicate<IUnresolvedMethod> filter = null, GetMemberOptions options = GetMemberOptions.IgnoreInheritedMembers)
{
if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) {
if (this.HasDefaultConstructorConstraint || this.HasValueTypeConstraint) {
if (filter == null || filter(dummyConstructor)) {
var resolvedCtor = (IMethod)dummyConstructor.CreateResolved(compilation.TypeResolveContext);
var resolvedCtor = GetDummyConstructor(compilation);
IMethod m = new SpecializedMethod(this, resolvedCtor, EmptyList<IType>.Instance);
return new [] { m };
}

4
ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
throw new ArgumentNullException("methodDefinition");
this.methodDefinition = methodDefinition;
this.typeArguments = typeArguments;
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
if (methodDefinition.TypeParameters.Any(ConstraintNeedsSpecialization)) {
// The method is generic, and we need to specialize the type parameters
@ -170,7 +170,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -170,7 +170,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
b.Append(this.DeclaringType.ToString());
b.Append('.');
b.Append(this.Name);
if (typeArguments != null && typeArguments.Count > 0) {
if (typeArguments.Count > 0) {
b.Append('[');
for (int i = 0; i < typeArguments.Count; i++) {
if (i > 0) b.Append(", ");

27
ICSharpCode.NRefactory/TypeSystem/ParameterizedType.cs

@ -37,7 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -37,7 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
/// the type arguments.
/// </remarks>
[Serializable]
public sealed class ParameterizedType : IType, ISupportsInterning
public sealed class ParameterizedType : IType
{
readonly ITypeDefinition genericType;
readonly IType[] typeArguments;
@ -320,31 +320,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -320,31 +320,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
else
return new ParameterizedType(def, ta);
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
for (int i = 0; i < typeArguments.Length; i++) {
typeArguments[i] = provider.Intern(typeArguments[i]);
}
}
int ISupportsInterning.GetHashCodeForInterning()
{
return GetHashCode();
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ParameterizedType o = other as ParameterizedType;
if (o != null && genericType == o.genericType && typeArguments.Length == o.typeArguments.Length) {
for (int i = 0; i < typeArguments.Length; i++) {
if (typeArguments[i] != o.typeArguments[i])
return false;
}
return true;
}
return false;
}
}
/// <summary>

18
ICSharpCode.NRefactory/TypeSystem/PointerType.cs

@ -22,7 +22,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation; @@ -22,7 +22,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem
{
public sealed class PointerType : TypeWithElementType, ISupportsInterning
public sealed class PointerType : TypeWithElementType
{
public PointerType(IType elementType) : base(elementType)
{
@ -71,22 +71,6 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -71,22 +71,6 @@ namespace ICSharpCode.NRefactory.TypeSystem
{
return new PointerTypeReference(elementType.ToTypeReference());
}
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725811;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
PointerType o = other as PointerType;
return o != null && this.elementType == o.elementType;
}
}
[Serializable]

Loading…
Cancel
Save