Browse Source

CSharpAstResolver now can resolve type members even when no parsedFile is specified.

This is useful for analyzing generated code that does not have accurate StartLocation/EndLocation assigned.
newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
4d07b33b44
  1. 13
      ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs
  2. 32
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
  3. 224
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  4. 12
      ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs
  5. 4
      ICSharpCode.NRefactory.ConsistencyCheck/Program.cs
  6. 8
      ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs
  7. 53
      ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
  8. 2
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs

13
ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/IndexerDeclaration.cs

@ -24,6 +24,7 @@ @@ -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 @@ -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 @@ -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)

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

@ -42,16 +42,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -42,16 +42,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// Use this overload if you are resolving within a complete C# file.
/// </summary>
/// <param name="compilation">The current compilation.</param>
/// <param name="compilationUnit">The compilation unit corresponding to the specified parsed file.</param>
/// <param name="parsedFile">
/// Result of the <see cref="TypeSystemConvertVisitor"/> 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 <see cref="TypeSystemConvertVisitor"/> for the file being resolved.
/// <para>
/// This is used for setting up the context on the resolver. The parsed file must be registered in the compilation.
/// </para>
/// <para>
/// 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 (<c>null</c> value for this parameter), the resolver will instead compare the
/// member's signature in the AST with the signature in the type system.
/// </para>
/// </param>
/// <param name="compilationUnit">The compilation unit corresponding to the specified parsed file.</param>
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 @@ -66,9 +73,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
/// <param name="resolver">The resolver state at the root node (to be more precise: outside the root node).</param>
/// <param name="rootNode">The root node of the resolved tree.</param>
/// <param name="parsedFile">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.</param>
/// <param name="parsedFile">
/// Optional: Result of the <see cref="TypeSystemConvertVisitor"/> for the file being resolved.
/// <para>
/// This is used for setting up the context on the resolver. The parsed file must be registered in the compilation.
/// </para>
/// <para>
/// 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 (<c>null</c> value for this parameter), the resolver will instead compare the
/// member's signature in the AST with the signature in the type system.
/// </para>
/// </param>
public CSharpAstResolver(CSharpResolver resolver, AstNode rootNode, CSharpParsedFile parsedFile = null)
{
if (resolver == null)

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

@ -515,8 +515,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -524,12 +529,50 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
void ApplyVisitorToUsings(TypeSystemConvertVisitor visitor, IEnumerable<AstNode> 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<ResolveResult>.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 @@ -591,26 +634,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Track CurrentMember
ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{
return VisitFieldOrEventDeclaration(fieldDeclaration);
return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field);
}
ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{
return VisitFieldOrEventDeclaration(fixedFieldDeclaration);
return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field);
}
ResolveResult IAstVisitor<ResolveResult>.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 @@ -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 @@ -734,6 +829,20 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
bool IsMatchingMethod(IMethod method, TypeParameterDeclaration[] typeParameters, IList<ITypeReference> 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<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{
return VisitMethodMember(methodDeclaration);
@ -759,20 +868,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -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 @@ -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 @@ -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 @@ -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

12
ICSharpCode.NRefactory.CSharp/TypeSystem/TypeSystemConvertVisitor.cs

@ -1139,6 +1139,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem @@ -1139,6 +1139,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
outputList.Add(p);
}
}
internal static IList<ITypeReference> GetParameterTypes(IEnumerable<ParameterDeclaration> parameters)
{
List<ITypeReference> result = new List<ITypeReference>();
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

4
ICSharpCode.NRefactory.ConsistencyCheck/Program.cs

@ -57,10 +57,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -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();

8
ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs

@ -147,7 +147,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -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 @@ -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 @@ -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 @@ -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

53
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -29,7 +29,7 @@ using ICSharpCode.NRefactory.TypeSystem; @@ -29,7 +29,7 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.ConsistencyCheck
{
/// <summary>
/// Description of ResolverTest.
/// Validates that no compile errors are found in valid code.
/// </summary>
public class ResolverTest
{
@ -38,10 +38,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -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 @@ -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<AstNode> resolvedNodes = new HashSet<AstNode>();
Dictionary<AstNode, ResolveResult> resolvedNodes = new Dictionary<AstNode, ResolveResult>();
HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>();
public ResolveVisitorNavigationMode Scan(AstNode node)
@ -62,10 +62,11 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck @@ -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 @@ -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 @@ -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);
}
}
}
}

2
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs

@ -35,6 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers @@ -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 @@ -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")

Loading…
Cancel
Save