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 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
@ -47,6 +48,16 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (PrivateImplementationTypeRole, value); } 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 { public CSharpTokenNode LBracketToken {
get { return GetChildByRole (Roles.LBracket); } get { return GetChildByRole (Roles.LBracket); }
} }
@ -95,7 +106,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
IndexerDeclaration o = other as IndexerDeclaration; 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.MatchAttributesAndModifiers(o, match) && this.ReturnType.DoMatch(o.ReturnType, match)
&& this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match) && this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match)
&& this.Parameters.DoMatch(o.Parameters, match) && this.Parameters.DoMatch(o.Parameters, match)

32
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. /// Use this overload if you are resolving within a complete C# file.
/// </summary> /// </summary>
/// <param name="compilation">The current compilation.</param> /// <param name="compilation">The current compilation.</param>
/// <param name="compilationUnit">The compilation unit corresponding to the specified parsed file.</param>
/// <param name="parsedFile"> /// <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>
/// <param name="compilationUnit">The compilation unit corresponding to the specified parsed file.</param> public CSharpAstResolver(ICompilation compilation, CompilationUnit compilationUnit, CSharpParsedFile parsedFile = null)
public CSharpAstResolver(ICompilation compilation, CompilationUnit compilationUnit, CSharpParsedFile parsedFile)
{ {
if (compilation == null) if (compilation == null)
throw new ArgumentNullException("compilation"); throw new ArgumentNullException("compilation");
if (parsedFile == null)
throw new ArgumentNullException("parsedFile");
if (compilationUnit == null) if (compilationUnit == null)
throw new ArgumentNullException("compilationUnit"); throw new ArgumentNullException("compilationUnit");
this.initialResolverState = new CSharpResolver(compilation); this.initialResolverState = new CSharpResolver(compilation);
@ -66,9 +73,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
/// <param name="resolver">The resolver state at the root node (to be more precise: outside the root node).</param> /// <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="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 /// <param name="parsedFile">
/// when the root node is on the type level; it is not necessary when an expression is passed. /// Optional: Result of the <see cref="TypeSystemConvertVisitor"/> for the file being resolved.
/// This parameter may be null.</param> /// <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) public CSharpAstResolver(CSharpResolver resolver, AstNode rootNode, CSharpParsedFile parsedFile = null)
{ {
if (resolver == null) if (resolver == null)

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

@ -515,8 +515,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
CSharpResolver previousResolver = resolver; CSharpResolver previousResolver = resolver;
try { try {
if (parsedFile != null) if (parsedFile != null) {
resolver = resolver.WithCurrentUsingScope(parsedFile.RootUsingScope.Resolve(resolver.Compilation)); 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); ScanChildren(unit);
return voidResult; return voidResult;
} finally { } finally {
@ -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) ResolveResult IAstVisitor<ResolveResult>.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration)
{ {
CSharpResolver previousResolver = resolver; CSharpResolver previousResolver = resolver;
try { try {
if (parsedFile != null) { if (parsedFile != null) {
resolver = resolver.WithCurrentUsingScope(parsedFile.GetUsingScope(namespaceDeclaration.StartLocation).Resolve(resolver.Compilation)); 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); ScanChildren(namespaceDeclaration);
// merge undecided lambdas before leaving the using scope so that // merge undecided lambdas before leaving the using scope so that
@ -591,26 +634,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Track CurrentMember #region Track CurrentMember
ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration) ResolveResult IAstVisitor<ResolveResult>.VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{ {
return VisitFieldOrEventDeclaration(fieldDeclaration); return VisitFieldOrEventDeclaration(fieldDeclaration, EntityType.Field);
} }
ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) ResolveResult IAstVisitor<ResolveResult>.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration)
{ {
return VisitFieldOrEventDeclaration(fixedFieldDeclaration); return VisitFieldOrEventDeclaration(fixedFieldDeclaration, EntityType.Field);
} }
ResolveResult IAstVisitor<ResolveResult>.VisitEventDeclaration(EventDeclaration eventDeclaration) 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; //int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(Roles.Variable).Count;
CSharpResolver oldResolver = resolver; CSharpResolver oldResolver = resolver;
for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) { for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) {
if (node.Role == Roles.Variable) { 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); Scan(node);
@ -717,16 +771,57 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
} }
ResolveResult VisitMethodMember(EntityDeclaration member) ResolveResult VisitMethodMember(EntityDeclaration memberDeclaration)
{ {
CSharpResolver oldResolver = resolver; CSharpResolver oldResolver = resolver;
try { try {
resolver = resolver.WithCurrentMember(GetMemberFromLocation(member.StartLocation)); IMember member = null;
if (parsedFile != null) {
ScanChildren(member); 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) if (member != null)
return new MemberResolveResult(null, resolver.CurrentMember, false); return new MemberResolveResult(null, member, false);
else else
return errorResult; return errorResult;
} finally { } finally {
@ -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) ResolveResult IAstVisitor<ResolveResult>.VisitMethodDeclaration(MethodDeclaration methodDeclaration)
{ {
return VisitMethodMember(methodDeclaration); return VisitMethodMember(methodDeclaration);
@ -759,20 +868,51 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
CSharpResolver oldResolver = resolver; CSharpResolver oldResolver = resolver;
try { 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) { 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.PushBlock();
resolver = resolver.AddVariable(new DefaultParameter(resolver.CurrentMember.ReturnType, "value")); resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
Scan(node); Scan(node);
resolver = resolver.PopBlock(); resolver = resolver.PopBlock();
} else { } else {
Scan(node); Scan(node);
} }
} }
if (resolver.CurrentMember != null) if (member != null)
return new MemberResolveResult(null, resolver.CurrentMember, false); return new MemberResolveResult(null, member, false);
else else
return errorResult; return errorResult;
} finally { } finally {
@ -794,18 +934,38 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
CSharpResolver oldResolver = resolver; CSharpResolver oldResolver = resolver;
try { 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.PushBlock();
resolver = resolver.AddVariable(new DefaultParameter(resolver.CurrentMember.ReturnType, "value")); resolver = resolver.AddVariable(new DefaultParameter(member.ReturnType, "value"));
ScanChildren(eventDeclaration); ScanChildren(eventDeclaration);
} else { } else {
ScanChildren(eventDeclaration); ScanChildren(eventDeclaration);
} }
if (resolver.CurrentMember != null) if (member != null)
return new MemberResolveResult(null, resolver.CurrentMember, false); return new MemberResolveResult(null, member, false);
else else
return errorResult; return errorResult;
} finally { } finally {
@ -876,16 +1036,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
try { try {
// Scan enum member attributes before setting resolver.CurrentMember, so that // Scan enum member attributes before setting resolver.CurrentMember, so that
// enum values used as attribute arguments have the correct type. // 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) foreach (var attributeSection in enumMemberDeclaration.Attributes)
Scan(attributeSection); 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) { if (resolverEnabled && resolver.CurrentTypeDefinition != null) {
ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType); ResolveAndProcessConversion(enumMemberDeclaration.Initializer, resolver.CurrentTypeDefinition.EnumUnderlyingType);
if (resolverEnabled && resolver.CurrentMember != null) if (resolverEnabled && member != null)
return new MemberResolveResult(null, resolver.CurrentMember, false); return new MemberResolveResult(null, member, false);
else else
return errorResult; return errorResult;
} else { } else {
@ -1747,7 +1914,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
DomRegion MakeRegion(AstNode node) 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 sealed class ExplicitlyTypedLambda : LambdaBase

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

@ -1139,6 +1139,18 @@ namespace ICSharpCode.NRefactory.CSharp.TypeSystem
outputList.Add(p); 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 #endregion
#region XML Documentation #region XML Documentation

4
ICSharpCode.NRefactory.ConsistencyCheck/Program.cs

@ -57,10 +57,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
solution.AllFiles.Count(), solution.AllFiles.Count(),
solution.Projects.Count); solution.Projects.Count);
using (new Timer("ID String test... ")) //using (new Timer("ID String test... ")) IDStringConsistencyCheck.Run(solution);
IDStringConsistencyCheck.Run(solution);
//RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest); //RunTestOnAllFiles("Roundtripping test", RoundtripTest.RunTest);
RunTestOnAllFiles("Resolver test", ResolverTest.RunTest); RunTestOnAllFiles("Resolver test", ResolverTest.RunTest);
RunTestOnAllFiles("Resolver test (no parsed file)", ResolverTest.RunTestWithoutParsedFile);
RunTestOnAllFiles("Resolver test (randomized order)", RandomizedOrderResolverTest.RunTest); RunTestOnAllFiles("Resolver test (randomized order)", RandomizedOrderResolverTest.RunTest);
new FindReferencesConsistencyCheck(solution).Run(); new FindReferencesConsistencyCheck(solution).Run();

8
ICSharpCode.NRefactory.ConsistencyCheck/RandomizedOrderResolverTest.cs

@ -147,7 +147,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return false; return false;
} }
bool IsEqualResolveResult(ResolveResult rr1, ResolveResult rr2) internal static bool IsEqualResolveResult(ResolveResult rr1, ResolveResult rr2)
{ {
if (rr1 == rr2) if (rr1 == rr2)
return true; return true;
@ -169,7 +169,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return eq; return eq;
} }
bool Compare(object val1, object val2, Type type) static bool Compare(object val1, object val2, Type type)
{ {
if (val1 == val2) if (val1 == val2)
return true; 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) if (r1.CheckForOverflow != r2.CheckForOverflow)
return false; return false;
@ -226,7 +226,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return r1.LocalVariables.Zip(r2.LocalVariables, IsEqualVariable).All(_ => _); 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) return object.Equals(v1.ConstantValue, v2.ConstantValue)
&& v1.IsConst == v2.IsConst && v1.IsConst == v2.IsConst

53
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -29,7 +29,7 @@ using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.ConsistencyCheck namespace ICSharpCode.NRefactory.ConsistencyCheck
{ {
/// <summary> /// <summary>
/// Description of ResolverTest. /// Validates that no compile errors are found in valid code.
/// </summary> /// </summary>
public class ResolverTest public class ResolverTest
{ {
@ -38,10 +38,10 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
CSharpAstResolver resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile); CSharpAstResolver resolver = new CSharpAstResolver(file.Project.Compilation, file.CompilationUnit, file.ParsedFile);
var navigator = new ValidatingResolveAllNavigator(file.FileName); var navigator = new ValidatingResolveAllNavigator(file.FileName);
resolver.ApplyNavigator(navigator, CancellationToken.None); resolver.ApplyNavigator(navigator, CancellationToken.None);
navigator.Validate(file.CompilationUnit); navigator.Validate(resolver, file.CompilationUnit);
} }
sealed class ValidatingResolveAllNavigator : IResolveVisitorNavigator class ValidatingResolveAllNavigator : IResolveVisitorNavigator
{ {
string fileName; string fileName;
bool allowErrors; 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")); 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>(); HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>();
public ResolveVisitorNavigationMode Scan(AstNode node) public ResolveVisitorNavigationMode Scan(AstNode node)
@ -62,10 +62,11 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
return ResolveVisitorNavigationMode.Resolve; 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"); throw new InvalidOperationException("Duplicate Resolved() call");
resolvedNodes.Add(node, result);
if (CSharpAstResolver.IsUnresolvableNode(node)) if (CSharpAstResolver.IsUnresolvableNode(node))
throw new InvalidOperationException("Resolved unresolvable 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)) if (!nodesWithConversions.Add(expression))
throw new InvalidOperationException("Duplicate ProcessConversion() call"); 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)) { if (!CSharpAstResolver.IsUnresolvableNode(node)) {
Console.WriteLine("Forgot to resolve " + 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
Assert.AreEqual(Modifiers.Public, id.Modifiers); Assert.AreEqual(Modifiers.Public, id.Modifiers);
Assert.AreEqual(Modifiers.None, id.Getter.Modifiers); Assert.AreEqual(Modifiers.None, id.Getter.Modifiers);
Assert.AreEqual(Modifiers.Protected, id.Setter.Modifiers); Assert.AreEqual(Modifiers.Protected, id.Setter.Modifiers);
Assert.AreEqual("Item", id.Name);
} }
[Test] [Test]
@ -59,7 +60,6 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
Identifier = "MyInterface", Identifier = "MyInterface",
TypeArguments = { new PrimitiveType("string") } TypeArguments = { new PrimitiveType("string") }
}, },
Name = "this",
Parameters = { Parameters = {
new ParameterDeclaration(new PrimitiveType("int"), "a"), new ParameterDeclaration(new PrimitiveType("int"), "a"),
new ParameterDeclaration(new PrimitiveType("string"), "b") new ParameterDeclaration(new PrimitiveType("string"), "b")

Loading…
Cancel
Save