Browse Source

CSharpAstResolver: don't return the same ResolveResult for two different nodes.

(make clones when using caches)
Closes icsharpcode/NRefactory#46.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
585ae50c2f
  1. 20
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  2. 19
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  3. 4
      ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs
  4. 6
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/LinqTests.cs
  5. 10
      ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs
  6. 5
      ICSharpCode.NRefactory/Semantics/ResolveResult.cs
  7. 4
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs

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

@ -41,8 +41,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public class CSharpResolver public class CSharpResolver
{ {
static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError; static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError;
static readonly ResolveResult DynamicResult = new ResolveResult(SpecialType.Dynamic);
static readonly ResolveResult NullResult = new ResolveResult(SpecialType.NullType);
readonly ICompilation compilation; readonly ICompilation compilation;
internal readonly CSharpConversions conversions; internal readonly CSharpConversions conversions;
@ -1381,7 +1379,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foundInCache = cache.TryGetValue(identifier, out r); foundInCache = cache.TryGetValue(identifier, out r);
} }
} }
if (!foundInCache) { if (foundInCache) {
r = (r != null ? r.ShallowClone() : null);
} else {
r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType); r = LookInCurrentType(identifier, typeArguments, lookupMode, parameterizeResultType);
if (cache != null) { if (cache != null) {
// also cache missing members (r==null) // also cache missing members (r==null)
@ -1398,9 +1398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
r = LookInUsingScopeNamespace(null, compilation.RootNamespace, identifier, typeArguments, parameterizeResultType); r = LookInUsingScopeNamespace(null, compilation.RootNamespace, identifier, typeArguments, parameterizeResultType);
} else { } else {
if (k == 0 && lookupMode != NameLookupMode.TypeInUsingDeclaration) { if (k == 0 && lookupMode != NameLookupMode.TypeInUsingDeclaration) {
if (!context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) { if (context.CurrentUsingScope.ResolveCache.TryGetValue(identifier, out r)) {
r = (r != null ? r.ShallowClone() : null);
} else {
r = LookInCurrentUsingScope(identifier, typeArguments, false, false); r = LookInCurrentUsingScope(identifier, typeArguments, false, false);
r = context.CurrentUsingScope.ResolveCache.GetOrAdd(identifier, r); context.CurrentUsingScope.ResolveCache.TryAdd(identifier, r);
} }
} else { } else {
r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == NameLookupMode.TypeInUsingDeclaration, parameterizeResultType); r = LookInCurrentUsingScope(identifier, typeArguments, lookupMode == NameLookupMode.TypeInUsingDeclaration, parameterizeResultType);
@ -1477,7 +1479,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!(isInUsingDeclaration && u == currentUsingScope)) { if (!(isInUsingDeclaration && u == currentUsingScope)) {
foreach (var pair in u.UsingAliases) { foreach (var pair in u.UsingAliases) {
if (pair.Key == identifier) { if (pair.Key == identifier) {
return pair.Value; return pair.Value.ShallowClone();
} }
} }
} }
@ -1589,7 +1591,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
if (target.Type.Kind == TypeKind.Dynamic) if (target.Type.Kind == TypeKind.Dynamic)
return DynamicResult; return new ResolveResult(SpecialType.Dynamic);
MemberLookup lookup = CreateMemberLookup(lookupMode); MemberLookup lookup = CreateMemberLookup(lookupMode);
ResolveResult result; ResolveResult result;
@ -1887,7 +1889,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §7.6.5 // C# 4.0 spec: §7.6.5
if (target.Type.Kind == TypeKind.Dynamic) if (target.Type.Kind == TypeKind.Dynamic)
return DynamicResult; return new ResolveResult(SpecialType.Dynamic);
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) { if (mgrr != null) {
@ -2297,7 +2299,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ResolveResult ResolvePrimitive(object value) public ResolveResult ResolvePrimitive(object value)
{ {
if (value == null) { if (value == null) {
return NullResult; return new ResolveResult(SpecialType.NullType);
} else { } else {
TypeCode typeCode = Type.GetTypeCode(value.GetType()); TypeCode typeCode = Type.GetTypeCode(value.GetType());
IType type = compilation.FindType(typeCode); IType type = compilation.FindType(typeCode);

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

@ -59,7 +59,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// The ResolveVisitor is also responsible for handling lambda expressions. // The ResolveVisitor is also responsible for handling lambda expressions.
static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError; static readonly ResolveResult errorResult = ErrorResolveResult.UnknownError;
readonly ResolveResult voidResult;
CSharpResolver resolver; CSharpResolver resolver;
/// <summary>Resolve result of the current LINQ query.</summary> /// <summary>Resolve result of the current LINQ query.</summary>
@ -112,13 +111,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.resolver = resolver; this.resolver = resolver;
this.parsedFile = parsedFile; this.parsedFile = parsedFile;
this.navigator = skipAllNavigator; this.navigator = skipAllNavigator;
this.voidResult = new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
} }
internal void SetNavigator(IResolveVisitorNavigator navigator) internal void SetNavigator(IResolveVisitorNavigator navigator)
{ {
this.navigator = navigator ?? skipAllNavigator; this.navigator = navigator ?? skipAllNavigator;
} }
ResolveResult voidResult {
get {
return new ResolveResult(resolver.Compilation.FindType(KnownTypeCode.Void));
}
}
#endregion #endregion
#region ResetContext #region ResetContext
@ -1594,7 +1598,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression) ResolveResult IAstVisitor<ResolveResult>.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
{ {
if (resolverEnabled) { if (resolverEnabled) {
return Resolve(typeReferenceExpression.Type); return Resolve(typeReferenceExpression.Type).ShallowClone();
} else { } else {
Scan(typeReferenceExpression.Type); Scan(typeReferenceExpression.Type);
return null; return null;
@ -2420,6 +2424,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
internal abstract AstNode BodyExpression { get; } internal abstract AstNode BodyExpression { get; }
internal abstract void EnforceMerge(ResolveVisitor parentVisitor); internal abstract void EnforceMerge(ResolveVisitor parentVisitor);
public override ResolveResult ShallowClone()
{
if (IsUndecided)
throw new NotSupportedException();
return base.ShallowClone();
}
} }
void MergeUndecidedLambdas() void MergeUndecidedLambdas()
@ -3261,7 +3272,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
foreach (var clause in queryExpression.Clauses) { foreach (var clause in queryExpression.Clauses) {
currentQueryResult = Resolve(clause); currentQueryResult = Resolve(clause);
} }
return currentQueryResult; return WrapResult(currentQueryResult);
} finally { } finally {
currentQueryResult = oldQueryResult; currentQueryResult = oldQueryResult;
cancellationToken = oldCancellationToken; cancellationToken = oldCancellationToken;

4
ICSharpCode.NRefactory.ConsistencyCheck/ResolverTest.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
} }
Dictionary<AstNode, ResolveResult> resolvedNodes = new Dictionary<AstNode, ResolveResult>(); Dictionary<AstNode, ResolveResult> resolvedNodes = new Dictionary<AstNode, ResolveResult>();
HashSet<ResolveResult> resolveResults = new HashSet<ResolveResult>();
HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>(); HashSet<AstNode> nodesWithConversions = new HashSet<AstNode>();
public ResolveVisitorNavigationMode Scan(AstNode node) public ResolveVisitorNavigationMode Scan(AstNode node)
@ -69,6 +70,9 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck
resolvedNodes.Add(node, result); resolvedNodes.Add(node, result);
if (CSharpAstResolver.IsUnresolvableNode(node)) if (CSharpAstResolver.IsUnresolvableNode(node))
throw new InvalidOperationException("Resolved unresolvable node"); throw new InvalidOperationException("Resolved unresolvable node");
if (!ParenthesizedExpression.ActsAsParenthesizedExpression(node))
if (!resolveResults.Add(result))
throw new InvalidOperationException("Duplicate resolve result");
if (result.IsError && !allowErrors) { if (result.IsError && !allowErrors) {
Console.WriteLine("Compiler error at " + fileName + ":" + node.StartLocation + ": " + result); Console.WriteLine("Compiler error at " + fileName + ":" + node.StartLocation + ": " + result);

6
ICSharpCode.NRefactory.Tests/CSharp/Resolver/LinqTests.cs

@ -103,8 +103,8 @@ class TestClass {
} }
} }
"; ";
var rr = Resolve<CSharpInvocationResolveResult>(program); var rr = Resolve<ConversionResolveResult>(program);
Assert.AreEqual("System.Linq.Enumerable.Select", rr.Member.FullName); Assert.IsTrue(rr.Conversion.IsIdentityConversion);
Assert.AreEqual("System.Collections.Generic.IEnumerable", rr.Type.FullName); Assert.AreEqual("System.Collections.Generic.IEnumerable", rr.Type.FullName);
Assert.AreEqual("System.Int32", ((ParameterizedType)rr.Type).TypeArguments[0].FullName); Assert.AreEqual("System.Int32", ((ParameterizedType)rr.Type).TypeArguments[0].FullName);
} }
@ -114,7 +114,7 @@ class TestClass {
{ {
string program = @"using System; string program = @"using System;
class TestClass { static void M() { class TestClass { static void M() {
$(from a in new XYZ() select a.ToUpper())$.ToString(); (from a in new XYZ() $select a.ToUpper()$).ToString();
}} }}
class XYZ { class XYZ {
public int Select<U>(Func<string, U> f) { return 42; } public int Select<U>(Func<string, U> f) { return 42; }

10
ICSharpCode.NRefactory/Semantics/MemberResolveResult.cs

@ -75,6 +75,16 @@ namespace ICSharpCode.NRefactory.Semantics
this.constantValue = constantValue; this.constantValue = constantValue;
} }
public MemberResolveResult(ResolveResult targetResult, IMember member, IType returnType, bool isConstant, object constantValue, bool isVirtualCall)
: base(returnType)
{
this.targetResult = targetResult;
this.member = member;
this.isConstant = isConstant;
this.constantValue = constantValue;
this.isVirtualCall = isVirtualCall;
}
public ResolveResult TargetResult { public ResolveResult TargetResult {
get { return targetResult; } get { return targetResult; }
} }

5
ICSharpCode.NRefactory/Semantics/ResolveResult.cs

@ -70,5 +70,10 @@ namespace ICSharpCode.NRefactory.Semantics
{ {
return DomRegion.Empty; return DomRegion.Empty;
} }
public virtual ResolveResult ShallowClone()
{
return (ResolveResult)MemberwiseClone();
}
} }
} }

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

@ -63,7 +63,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
IType type = typeReference.Resolve(context); IType type = typeReference.Resolve(context);
IEnumerable<IMember> members; IEnumerable<IMember> members;
if (entityType == EntityType.Accessor) { if (entityType == EntityType.Accessor) {
members = type.GetAccessors(m => m.Name == name && !m.IsExplicitInterfaceImplementation); members = type.GetAccessors(
m => m.Name == name && !m.IsExplicitInterfaceImplementation,
GetMemberOptions.IgnoreInheritedMembers);
} else if (entityType == EntityType.Method) { } else if (entityType == EntityType.Method) {
members = type.GetMethods( members = type.GetMethods(
m => m.Name == name && m.EntityType == EntityType.Method m => m.Name == name && m.EntityType == EntityType.Method

Loading…
Cancel
Save