diff --git a/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs b/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
index c175485ab5..02bc126aec 100644
--- a/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
+++ b/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
@@ -24,6 +24,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
@@ -47,6 +48,16 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (PrivateImplementationTypeRole, value); }
}
+ public override string Name {
+ get { return "Item"; }
+ set { throw new NotSupportedException(); }
+ }
+
+ public override Identifier NameToken {
+ get { return Identifier.Null; }
+ set { throw new NotSupportedException(); }
+ }
+
public CSharpTokenNode LBracketToken {
get { return GetChildByRole (Roles.LBracket); }
}
@@ -95,7 +106,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
IndexerDeclaration o = other as IndexerDeclaration;
- return o != null && MatchString(this.Name, o.Name)
+ return o != null
&& this.MatchAttributesAndModifiers(o, match) && this.ReturnType.DoMatch(o.ReturnType, match)
&& this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match)
&& this.Parameters.DoMatch(o.Parameters, match)
diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
index 6c06be7e06..234e17f261 100644
--- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
+++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
@@ -42,16 +42,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Use this overload if you are resolving within a complete C# file.
///
/// The current compilation.
+ /// The compilation unit corresponding to the specified parsed file.
///
- /// Result of the for the file being passed. This is used for setting up the context on the resolver. The parsed file must be registered in the compilation.
+ /// Optional: Result of the for the file being resolved.
+ ///
+ /// This is used for setting up the context on the resolver. The parsed file must be registered in the compilation.
+ ///
+ ///
+ /// When a parsedFile is specified, the resolver will use the member's StartLocation/EndLocation to identify
+ /// member declarations in the AST with members in the type system.
+ /// When no parsedFile is specified (null value for this parameter), the resolver will instead compare the
+ /// member's signature in the AST with the signature in the type system.
+ ///
///
- /// The compilation unit corresponding to the specified parsed file.
- public CSharpAstResolver(ICompilation compilation, CompilationUnit compilationUnit, CSharpParsedFile parsedFile)
+ public CSharpAstResolver(ICompilation compilation, CompilationUnit compilationUnit, CSharpParsedFile parsedFile = null)
{
if (compilation == null)
throw new ArgumentNullException("compilation");
- if (parsedFile == null)
- throw new ArgumentNullException("parsedFile");
if (compilationUnit == null)
throw new ArgumentNullException("compilationUnit");
this.initialResolverState = new CSharpResolver(compilation);
@@ -66,9 +73,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
/// The resolver state at the root node (to be more precise: outside the root node).
/// The root node of the resolved tree.
- /// The parsed file for the nodes being resolved. This parameter is used only
- /// when the root node is on the type level; it is not necessary when an expression is passed.
- /// This parameter may be null.
+ ///
+ /// Optional: Result of the for the file being resolved.
+ ///
+ /// This is used for setting up the context on the resolver. The parsed file must be registered in the compilation.
+ ///
+ ///
+ /// When a parsedFile is specified, the resolver will use the member's StartLocation/EndLocation to identify
+ /// member declarations in the AST with members in the type system.
+ /// When no parsedFile is specified (null value for this parameter), the resolver will instead compare the
+ /// member's signature in the AST with the signature in the type system.
+ ///
+ ///
public CSharpAstResolver(CSharpResolver resolver, AstNode rootNode, CSharpParsedFile parsedFile = null)
{
if (resolver == null)
diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
index eed5b3e8ac..0e395b51cd 100644
--- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
+++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
@@ -515,8 +515,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
CSharpResolver previousResolver = resolver;
try {
- if (parsedFile != null)
+ if (parsedFile != null) {
resolver = resolver.WithCurrentUsingScope(parsedFile.RootUsingScope.Resolve(resolver.Compilation));
+ } else {
+ var cv = new TypeSystemConvertVisitor(unit.FileName ?? string.Empty);
+ ApplyVisitorToUsings(cv, unit.Children);
+ PushUsingScope(cv.ParsedFile.RootUsingScope);
+ }
ScanChildren(unit);
return voidResult;
} finally {
@@ -524,12 +529,50 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
+ void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable children)
+ {
+ foreach (var child in children) {
+ if (child is ExternAliasDeclaration || child is UsingDeclaration || child is UsingAliasDeclaration) {
+ child.AcceptVisitor(visitor);
+ }
+ }
+ }
+
+ void PushUsingScope(UsingScope usingScope)
+ {
+ usingScope.Freeze();
+ resolver = resolver.WithCurrentUsingScope(new ResolvedUsingScope(resolver.CurrentTypeResolveContext, usingScope));
+ }
+
ResolveResult IAstVisitor.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
{
CSharpResolver previousResolver = resolver;
try {
if (parsedFile != null) {
resolver = resolver.WithCurrentUsingScope(parsedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation));
+ } else {
+ string fileName = namespaceDeclaration.GetRegion().FileName ?? string.Empty;
+ // Fetch parent using scope
+ // Create root using scope if necessary
+ if (resolver.CurrentUsingScope == null)
+ PushUsingScope(new UsingScope());
+
+ // Create child using scope
+ DomRegion region = namespaceDeclaration.GetRegion();
+ var identifiers = namespaceDeclaration.Identifiers.ToList();
+ // For all but the last identifier:
+ UsingScope usingScope;
+ for (int i = 0; i < identifiers.Count - 1; i++) {
+ usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers[i].Name);
+ usingScope.Region = region;
+ PushUsingScope(usingScope);
+ }
+ // Last using scope:
+ usingScope = new UsingScope(resolver.CurrentUsingScope.UnresolvedUsingScope, identifiers.Last().Name);
+ usingScope.Region = region;
+ var cv = new TypeSystemConvertVisitor(new CSharpParsedFile(region.FileName ?? string.Empty), usingScope);
+ ApplyVisitorToUsings(cv, namespaceDeclaration.Children);
+ PushUsingScope(usingScope);
}
ScanChildren(namespaceDeclaration);
// merge undecided lambdas before leaving the using scope so that
@@ -591,26 +634,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Track CurrentMember
ResolveResult IAstVisitor.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{
- return VisitFieldOrEventDeclaration(fieldDeclaration);
+ return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field);
}
ResolveResult IAstVisitor.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{
- return VisitFieldOrEventDeclaration(fixedFieldDeclaration);
+ return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field);
}
ResolveResult IAstVisitor.VisitEventDeclaration(EventDeclaration eventDeclaration)
{
- return VisitFieldOrEventDeclaration(eventDeclaration);
+ return VisitFieldOrEventDeclaration(eventDeclaration, EntityType.Event);
}
- ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration)
+ ResolveResult VisitFieldOrEventDeclaration(EntityDeclaration fieldOrEventDeclaration, EntityType entityType)
{
//int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count;
CSharpResolver oldResolver = resolver;
for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == Roles.Variable) {
- resolver = resolver.WithCurrentMember(GetMemberFromLocation(node.StartLocation));
+ IMember member = null;
+ if (parsedFile != null) {
+ member = GetMemberFromLocation(node.StartLocation);
+ } else if (resolver.CurrentTypeDefinition != null) {
+ string name = ((VariableInitializer)node).Name;
+ if (entityType == EntityType.Event) {
+ member = resolver.CurrentTypeDefinition.GetEvents(e => e.Name == name && !e.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
+ } else {
+ member = resolver.CurrentTypeDefinition.GetFields(e => e.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
+ }
+ }
+ resolver = resolver.WithCurrentMember(member);
Scan(node);
@@ -717,16 +771,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
- ResolveResult VisitMethodMember(EntityDeclaration member)
+ ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration)
{
CSharpResolver oldResolver = resolver;
try {
- resolver = resolver.WithCurrentMember(GetMemberFromLocation(member.StartLocation));
-
- ScanChildren(member);
+ IMember member = null;
+ if (parsedFile != null) {
+ member = GetMemberFromLocation(memberDeclaration.StartLocation);
+ } else if (resolver.CurrentTypeDefinition != null) {
+ // Re-discover the method:
+ EntityType entityType = memberDeclaration.EntityType;
+ var typeParameters = memberDeclaration.GetChildrenByRole(Roles.TypeParameter).ToArray();
+ var parameterTypes = TypeSystemConvertVisitor.GetParameterTypes(memberDeclaration.GetChildrenByRole(Roles.Parameter));
+ if (entityType == EntityType.Constructor) {
+ bool isStatic = memberDeclaration.HasModifier(Modifiers.Static);
+ member = resolver.CurrentTypeDefinition.Methods.FirstOrDefault(
+ m => m.EntityType == entityType && m.IsStatic == isStatic
+ && m.Parameters.Count == parameterTypes.Count
+ && IsMatchingMethod(m, typeParameters, parameterTypes));
+ } else {
+ string name = (entityType == EntityType.Destructor ? "Finalize" : memberDeclaration.Name);
+ AstType explicitInterfaceAstType = memberDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
+ bool isExplicitInterfaceImplementation = false;
+ IType explicitInterfaceType = null;
+ if (!explicitInterfaceAstType.IsNull) {
+ isExplicitInterfaceImplementation = true;
+ explicitInterfaceType = explicitInterfaceAstType.ToTypeReference().Resolve(resolver.CurrentTypeResolveContext);
+ }
+ foreach (var method in resolver.CurrentTypeDefinition.GetMethods(
+ m => m.EntityType == entityType && m.Name == name
+ && m.TypeParameters.Count == typeParameters.Length && m.Parameters.Count == parameterTypes.Count
+ && m.IsExplicitInterfaceImplementation == isExplicitInterfaceImplementation,
+ GetMemberOptions.IgnoreInheritedMembers
+ )) {
+ if (isExplicitInterfaceImplementation) {
+ if (method.ImplementedInterfaceMembers.Count != 1)
+ continue;
+ if (!explicitInterfaceType.Equals(method.ImplementedInterfaceMembers[0].DeclaringType))
+ continue;
+ }
+ if (IsMatchingMethod(method, typeParameters, parameterTypes)) {
+ member = method;
+ break;
+ }
+ }
+ }
+ }
+ resolver = resolver.WithCurrentMember(member);
+ ScanChildren(memberDeclaration);
- if (resolver.CurrentMember != null)
- return new MemberResolveResult(null, resolver.CurrentMember, false);
+ if (member != null)
+ return new MemberResolveResult(null, member, false);
else
return errorResult;
} finally {
@@ -734,6 +829,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
+ bool IsMatchingMethod(IMethod method, TypeParameterDeclaration[] typeParameters, IList parameterTypes)
+ {
+ for (int i = 0; i < typeParameters.Length; i++) {
+ if (method.TypeParameters[i].Name != typeParameters[i].Name)
+ return false;
+ }
+ var resolvedParameterTypes = parameterTypes.Resolve(resolver.CurrentTypeResolveContext.WithCurrentMember(method));
+ for (int i = 0; i < parameterTypes.Count; i++) {
+ if (!method.Parameters[i].Type.Equals(resolvedParameterTypes[i]))
+ return false;
+ }
+ return true;
+ }
+
ResolveResult IAstVisitor.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
return VisitMethodMember(methodDeclaration);
@@ -759,20 +868,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
CSharpResolver oldResolver = resolver;
try {
- resolver = resolver.WithCurrentMember(GetMemberFromLocation(propertyOrIndexerDeclaration.StartLocation));
+ IMember member = null;
+ if (parsedFile != null) {
+ member = GetMemberFromLocation(propertyOrIndexerDeclaration.StartLocation);
+ } else if (resolver.CurrentTypeDefinition != null) {
+ // Re-discover the property:
+ string name = propertyOrIndexerDeclaration.Name;
+ var parameterTypeReferences = TypeSystemConvertVisitor.GetParameterTypes(propertyOrIndexerDeclaration.GetChildrenByRole(Roles.Parameter));
+ var parameterTypes = parameterTypeReferences.Resolve(resolver.CurrentTypeResolveContext);
+ AstType explicitInterfaceAstType = propertyOrIndexerDeclaration.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
+ bool isExplicitInterfaceImplementation = false;
+ IType explicitInterfaceType = null;
+ if (!explicitInterfaceAstType.IsNull) {
+ isExplicitInterfaceImplementation = true;
+ explicitInterfaceType = explicitInterfaceAstType.ToTypeReference().Resolve(resolver.CurrentTypeResolveContext);
+ }
+ foreach (IProperty property in resolver.CurrentTypeDefinition.GetProperties(
+ p => p.Name == name && p.Parameters.Count == parameterTypes.Count && p.IsExplicitInterfaceImplementation == isExplicitInterfaceImplementation,
+ GetMemberOptions.IgnoreInheritedMembers
+ )) {
+ if (isExplicitInterfaceImplementation) {
+ if (property.ImplementedInterfaceMembers.Count != 1)
+ continue;
+ if (!explicitInterfaceType.Equals(property.ImplementedInterfaceMembers[0].DeclaringType))
+ continue;
+ }
+ if (Enumerable.SequenceEqual(parameterTypes, property.Parameters.Select(p => p.Type))) {
+ member = property;
+ break;
+ }
+ }
+ }
+ resolver = resolver.WithCurrentMember(member);
for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) {
- if (node.Role == PropertyDeclaration.SetterRole && resolver.CurrentMember != null) {
+ if (node.Role == PropertyDeclaration.SetterRole && member != null) {
resolver = resolver.PushBlock();
- resolver = resolver.AddVariable(new DefaultParameter(resolver.CurrentMember.ReturnType, "value"));
+ resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
Scan(node);
resolver = resolver.PopBlock();
} else {
Scan(node);
}
}
- if (resolver.CurrentMember != null)
- return new MemberResolveResult(null, resolver.CurrentMember, false);
+ if (member != null)
+ return new MemberResolveResult(null, member, false);
else
return errorResult;
} finally {
@@ -794,18 +934,38 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
CSharpResolver oldResolver = resolver;
try {
- resolver = resolver.WithCurrentMember(GetMemberFromLocation(eventDeclaration.StartLocation));
+ IMember member = null;
+ if (parsedFile != null) {
+ member = GetMemberFromLocation(eventDeclaration.StartLocation);
+ } else if (resolver.CurrentTypeDefinition != null) {
+ string name = eventDeclaration.Name;
+ AstType explicitInterfaceAstType = eventDeclaration.PrivateImplementationType;
+ if (explicitInterfaceAstType.IsNull) {
+ member = resolver.CurrentTypeDefinition.GetEvents(
+ e => e.Name == name && !e.IsExplicitInterfaceImplementation,
+ GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
+ } else {
+ IType explicitInterfaceType = explicitInterfaceAstType.ToTypeReference().Resolve(resolver.CurrentTypeResolveContext);
+ member = resolver.CurrentTypeDefinition.GetEvents(
+ e => e.Name == name && e.IsExplicitInterfaceImplementation,
+ GetMemberOptions.IgnoreInheritedMembers
+ ).FirstOrDefault(
+ e => e.ImplementedInterfaceMembers.Count == 1 && explicitInterfaceType.Equals(e.ImplementedInterfaceMembers[0].DeclaringType)
+ );
+ }
+ }
+ resolver = resolver.WithCurrentMember(member);
- if (resolver.CurrentMember != null) {
+ if (member != null) {
resolver = resolver.PushBlock();
- resolver = resolver.AddVariable(new DefaultParameter(resolver.CurrentMember.ReturnType, "value"));
+ resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
ScanChildren(eventDeclaration);
} else {
ScanChildren(eventDeclaration);
}
- if (resolver.CurrentMember != null)
- return new MemberResolveResult(null, resolver.CurrentMember, false);
+ if (member != null)
+ return new MemberResolveResult(null, member, false);
else
return errorResult;
} finally {
@@ -876,16 +1036,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
try {
// Scan enum member attributes before setting resolver.CurrentMember, so that
// enum values used as attribute arguments have the correct type.
- // (which an enum member, all other enum members are treated as having their underlying type)
+ // (within an enum member, all other enum members are treated as having their underlying type)
foreach (var attributeSection in enumMemberDeclaration.Attributes)
Scan(attributeSection);
- resolver = resolver.WithCurrentMember(GetMemberFromLocation(enumMemberDeclaration.StartLocation));
+ IMember member = null;
+ if (parsedFile != null) {
+ member = GetMemberFromLocation(enumMemberDeclaration.StartLocation);
+ } else if (resolver.CurrentTypeDefinition != null) {
+ string name = enumMemberDeclaration.Name;
+ member = resolver.CurrentTypeDefinition.GetFields(f => f.Name == name, GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault();
+ }
+ resolver = resolver.WithCurrentMember(member);
if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
- if (resolverEnabled && resolver.CurrentMember != null)
- return new MemberResolveResult(null, resolver.CurrentMember, false);
+ if (resolverEnabled && member != null)
+ return new MemberResolveResult(null, member, false);
else
return errorResult;
} else {
@@ -1747,7 +1914,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
DomRegion MakeRegion(AstNode node)
{
- return new DomRegion(parsedFile != null ? parsedFile.FileName : null, node.StartLocation, node.EndLocation);
+ if (parsedFile != null)
+ return new DomRegion(parsedFile.FileName, node.StartLocation, node.EndLocation);
+ else
+ return node.GetRegion();
}
sealed class ExplicitlyTypedLambda : LambdaBase
diff --git a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
index 934e990e79..55c80e9c9a 100644
--- a/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
+++ b/ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
@@ -1139,6 +1139,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
outputList.Add(p);
}
}
+
+ internal static IList GetParameterTypes(IEnumerable parameters)
+ {
+ List result = new List();
+ foreach (ParameterDeclaration pd in parameters) {
+ ITypeReference type = pd.Type.ToTypeReference();
+ if (pd.ParameterModifier == ParameterModifier.Ref || pd.ParameterModifier == ParameterModifier.Out)
+ type = new ByReferenceTypeReference(type);
+ result.Add(type);
+ }
+ return result;
+ }
#endregion
#region XML Documentation
diff --git a/ICSharpCode.NRefactory.ConsistencyCheck/Program.cs b/ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
index 869b98a48a..b93c60f960 100644
--- a/ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
+++ b/ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
@@ -57,10 +57,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
solution.AllFiles.Count(),
solution.Projects.Count);
- using (new Timer("ID String test... "))
- IDStringConsistencyCheck.Run(solution);
+ //using (new Timer("ID String test... ")) IDStringConsistencyCheck.Run(solution);
//RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);
+ RunTestOnAllFiles("Resolver test (no parsed file)", ResolverTest.RunTestWithoutParsedFile);
RunTestOnAllFiles("Resolver test (randomized order)", RandomizedOrderResolverTest.RunTest);
new FindReferencesConsistencyCheck(solution).Run();
diff --git a/ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs b/ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs
index 4c1ad1f799..d6f9390bfc 100644
--- a/ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs
+++ b/ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs
@@ -147,7 +147,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return false;
}
- bool IsEqualResolveResult(ResolveResult rr1, ResolveResult rr2)
+ internal static bool IsEqualResolveResult(ResolveResult rr1, ResolveResult rr2)
{
if (rr1 == rr2)
return true;
@@ -169,7 +169,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return eq;
}
- bool Compare(object val1, object val2, Type type)
+ static bool Compare(object val1, object val2, Type type)
{
if (val1 == val2)
return true;
@@ -205,7 +205,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
}
}
- bool IsEqualResolverState(CSharpResolver r1, CSharpResolver r2)
+ internal static bool IsEqualResolverState(CSharpResolver r1, CSharpResolver r2)
{
if (r1.CheckForOverflow != r2.CheckForOverflow)
return false;
@@ -226,7 +226,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return r1.LocalVariables.Zip(r2.LocalVariables, IsEqualVariable).All(_ => _);
}
- bool IsEqualVariable(IVariable v1, IVariable v2)
+ internal static bool IsEqualVariable(IVariable v1, IVariable v2)
{
return object.Equals(v1.ConstantValue, v2.ConstantValue)
&& v1.IsConst == v2.IsConst
diff --git a/ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs b/ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
index a20e26135d..59f156eb8c 100644
--- a/ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
+++ b/ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
@@ -29,7 +29,7 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.ConsistencyCheck
{
///
- /// Description of ResolverTest.
+ /// Validates that no compile errors are found in valid code.
///
public class ResolverTest
{
@@ -38,10 +38,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
CSharpAstResolver resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
var navigator = new ValidatingResolveAllNavigator(file.FileName);
resolver.ApplyNavigator(navigator, CancellationToken.None);
- navigator.Validate(file.CompilationUnit);
+ navigator.Validate(resolver, file.CompilationUnit);
}
- sealed class ValidatingResolveAllNavigator : IResolveVisitorNavigator
+ class ValidatingResolveAllNavigator : IResolveVisitorNavigator
{
string fileName;
bool allowErrors;
@@ -54,7 +54,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
this.allowErrors = (fileName.Contains(".xaml") || File.Exists(Path.ChangeExtension(fileName, ".xaml")) || fileName.EndsWith("AvalonDockLayout.cs") || fileName.EndsWith("ResourcesFileTreeNode.cs") || fileName.EndsWith("ChangeMarkerMargin.cs"));
}
- HashSet resolvedNodes = new HashSet();
+ Dictionary resolvedNodes = new Dictionary();
HashSet nodesWithConversions = new HashSet();
public ResolveVisitorNavigationMode Scan(AstNode node)
@@ -62,10 +62,11 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return ResolveVisitorNavigationMode.Resolve;
}
- public void Resolved(AstNode node, ResolveResult result)
+ public virtual void Resolved(AstNode node, ResolveResult result)
{
- if (!resolvedNodes.Add(node))
+ if (resolvedNodes.ContainsKey(node))
throw new InvalidOperationException("Duplicate Resolved() call");
+ resolvedNodes.Add(node, result);
if (CSharpAstResolver.IsUnresolvableNode(node))
throw new InvalidOperationException("Resolved unresolvable node");
@@ -74,7 +75,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
}
}
- public void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
+ public virtual void ProcessConversion(Expression expression, ResolveResult result, Conversion conversion, IType targetType)
{
if (!nodesWithConversions.Add(expression))
throw new InvalidOperationException("Duplicate ProcessConversion() call");
@@ -83,13 +84,47 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
}
}
- public void Validate(CompilationUnit cu)
+ public virtual void Validate(CSharpAstResolver resolver, CompilationUnit cu)
{
- foreach (AstNode node in cu.DescendantsAndSelf.Except(resolvedNodes)) {
+ foreach (AstNode node in cu.DescendantsAndSelf.Except(resolvedNodes.Keys)) {
if (!CSharpAstResolver.IsUnresolvableNode(node)) {
Console.WriteLine("Forgot to resolve " + node);
}
}
+ foreach (var pair in resolvedNodes) {
+ if (resolver.Resolve(pair.Key) != pair.Value)
+ throw new InvalidOperationException("Inconsistent result");
+ }
+ }
+ }
+
+ public static void RunTestWithoutParsedFile(CSharpFile file)
+ {
+ CSharpAstResolver originalResolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
+ originalResolver.ApplyNavigator(new ValidatingResolveAllNavigator(file.FileName), CancellationToken.None);
+ CSharpAstResolver resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit);
+ var navigator = new ComparingResolveAllNavigator(originalResolver);
+ resolver.ApplyNavigator(navigator, CancellationToken.None);
+ navigator.Validate(resolver, file.CompilationUnit);
+ }
+
+ sealed class ComparingResolveAllNavigator : ValidatingResolveAllNavigator
+ {
+ readonly CSharpAstResolver originalResolver;
+
+ public ComparingResolveAllNavigator(CSharpAstResolver originalResolver)
+ : base(originalResolver.ParsedFile.FileName)
+ {
+ this.originalResolver = originalResolver;
+ }
+
+ public override void Resolved(AstNode node, ResolveResult result)
+ {
+ base.Resolved(node, result);
+ ResolveResult originalResult = originalResolver.Resolve(node);
+ if (!RandomizedOrderResolverTest.IsEqualResolveResult(originalResult, result)) {
+ Console.WriteLine("Compiler error at " + node.GetRegion().FileName + ":" + node.StartLocation + ": Should be " + originalResult + " but was " + result);
+ }
}
}
}
diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs
index 4cabc1d2bf..330a0fe2f0 100644
--- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs
+++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs
@@ -35,6 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
Assert.AreEqual(Modifiers.Public, id.Modifiers);
Assert.AreEqual(Modifiers.None, id.Getter.Modifiers);
Assert.AreEqual(Modifiers.Protected, id.Setter.Modifiers);
+ Assert.AreEqual("Item", id.Name);
}
[Test]
@@ -59,7 +60,6 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
Identifier = "MyInterface",
TypeArguments = { new PrimitiveType("string") }
},
- Name = "this",
Parameters = {
new ParameterDeclaration(new PrimitiveType("int"), "a"),
new ParameterDeclaration(new PrimitiveType("string"), "b")